スレッドによるアクセスの開始からアクセスの終了までのプロセス全体で、アクセス オブジェクトが他のスレッドによって変更されると、アクセス プロセス全体で現在のスレッドにスレッド セーフティの問題が発生します。 、オブジェクトはありません 他のスレッドによって変更されており、スレッドセーフです。
1 つ目はマルチスレッド環境です。つまり、同時に複数のオペレータが存在し、単一のオペレータではスレッド セーフティの問題は発生しません。 -スレッド環境。シングルスレッド環境では、変更操作を含むすべての操作はオペレーター自身によって発行されます。オペレーターは、操作を発行するときに明確な目的があるだけでなく、操作の影響も認識します。
複数のオペレーター (スレッド) が同じオブジェクトを操作する必要があります。複数のオペレーターが同時にオブジェクトを操作した場合にのみ、その動作の影響を他のオペレーターに即座に渡すことができます。
同じオブジェクトに対する複数の演算子 (スレッド) の操作には、変更操作が含まれている必要があります。オブジェクトは変更されておらず、影響を与えることもできないため、共同読み取りではスレッドの安全性の問題は発生しません。
上記のことから、スレッド セーフティの問題の根本原因は、共有データが同時に変更される可能性があること、つまり、1 つのスレッドが読み取りを行うときに、別のスレッドが変更できることであることがわかります。
スレッドの安全性の問題が発生する条件に応じて、スレッドの安全性の問題を解決するためのアイデアは、スレッドの安全性の問題を引き起こす環境を排除することです:
共有データの削除: メンバー変数 静的変数を複数のスレッドで共有し、これらのグローバル変数をローカル変数に変換し、ローカル変数をスタックに保存します。スレッド間で共有されない場合、スレッドの安全性の問題が発生する環境はありません。共有データの欠点を解消する: 各スレッドから情報を収集したり、スレッド間で情報を転送したりするためにオブジェクトが必要な場合、共有オブジェクトを削除するとこの目的を達成できなくなります。
スレッド同期メカニズムを使用します。読み取り操作と書き込み操作を同時にロックして、1 つのスレッドだけが同時に共有データにアクセスできるようにします。書き込み操作のみがロックされており、書き込み操作を同時に実行できるのは 1 つのスレッドのみであり、読み取り操作が制限されておらず、複数のスレッドが同時に読み取りできる場合、反復不可能な読み取り (次のような読み取り) が発生する可能性があります。スレッドが長時間にわたって配列の同じインデックス位置のデータを読み取ると、スレッドがそのインデックスのデータを変更し、スレッドによって同じインデックスから読み取られたデータが変更されます。一貫性がなくなる。読み取りと書き込みの両方をロックするか、書き込みのみをロックするかは、特定のニーズによって異なります。同期メカニズムの欠点は、プログラムのスループットが低下することです。
コピーの作成: ThreadLocal を使用して、各スレッドの変数のコピーを作成し、各スレッドは相互に影響を与えることなく独立して動作します。この方法は本質的に、データの共有という概念を排除する実装です。
4. 可視性はい、これは表示の問題です。
public class NoVisibility {
private static boolean ready;
private static int number;
public static class ReadThread extends Thread {
public void run() {
while(!ready )
Thread. yield();
System. out.println(number);
}
}
public static void main(String [] args) {
new ReadThread().start();
number = 42;
ready = true ;
}
}
上記のコードは 0 を出力するか、何も出力しない場合があります。何も出力できないのはなぜですか?メインスレッドではreadyをtrueに設定していますが、設定したready値はReadThreadでは読み取れない可能性があるため、ReadThreadではThread.yield()が実行され続けます。なぜ 0 になるのでしょうか? ReadThread が値を読み取ることができる場合、ReadThread は最初に準備完了の値が true であることを読み取り、数値を読み取り更新する前に、ReadThread は保持されている数値 (0) を出力します。
上記はすべて仮定であることに注意してください。同期がない場合に ReadThread とメインスレッドがどのように相互作用するかは予測できません。上記の 2 つの状況は 2 つの可能性があるだけです。では、この問題を回避するにはどうすればよいでしょうか?簡単なことは、複数のスレッド間でデータを共有する必要がある場合は常に、適切な同期を使用することです。
4.1、ロックと可視性
内置锁可以用于确保某个线程以一种可预测的方式查看另一个线程的执行结果,当线程A进入某同步代码块时,线程B随后进入由同一个锁保护的同步代码块,此时,线程B执行由锁保护的同步代码块时,可以看到线程A之前在同一同步代码块中的所有操作结果,如果没有同步,那么就无法实现上述保证。
加锁的含义不仅仅局限于互斥行为,还包括内存可见性。为了确保所有线程都能看到共享变量的最新值,所有执行读操作或者写操作的线程都必须在同一个锁上同步。
4.2、volatile变量
volatile是一种比synchronized关键字轻量级的同步机制,volatile关键字可以确保变量的更新操作通知到其他线程。
下面是volatile的典型用法:
volatile boolean asleep; ... while(!asleep) doSomeThing();
加锁机制既可以确保可见性,又可以确保原子性,而volatile变量只能确保可见性。
5、总结
编写线程安全的代码,其核心在于要对状态访问操作进行管理。编写线程安全的代码时,有两个关注点,一个是原子性问题,一个是可见性问题,要尽量避免竞态条件错误。
以上がマルチスレッドのセキュリティ問題の原理に関する Java の説明の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。