質問: 同期とスリープでも、揮発性スレッドの可視性という目的を達成できますか? 一般的な問題の説明は次のとおりです:
パッケージ com.test;
import java.util.concurrent.TimeUnit;
パブリック クラス test1 {
プライベート静的ブール値は = true;
public static void main(String[] args) {
new Thread(new Runnable() {
@オーバーライド###### public void run() {
int i = 0;
while(test1.is){
私 ;###### 1 //synchronized (this) { } は、メイン メモリの変数値をスレッド スタックに強制的に更新しますか?
2 //System.out.println("1"); println は同期されており、メイン メモリの変数値をスレッド スタックに強制的に更新しますか?
3 //スリープするとメインメモリの値がリロードされますか?
// 試す {###### // TimeUnit.MICROSECONDS.sleep(1);
// }catch (InterruptedException e) {
// e.printStackTrace();
// }
}
}
})。始める();###### 試す {###### TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
new Thread(new Runnable() {
@オーバーライド###### public void run() {
is = false; // 上記のスレッドが while ループを終了するように is を false に設定します。 }
})。始める();###### }
}
Q: プログラム全体が終了しないのはなぜですか?コード ブロック (1、2、3) のコメントを解除するとプログラムが終了するのはなぜですか?同期すると、メモリ変数値がスレッド スタックに強制的に更新されますか? スリープは何を行いますか?
知識を伴う説明
volatile: このキーワードは、スレッド内の変数の可視性を保証します。volatile によって変更された変数にアクセスするすべてのスレッドは、動作前にメイン メモリから読み取り、作業メモリが変更された直後にメイン メモリに書き戻す必要があります。これにより、他のスレッドの可視性、同じ効果を持つキーワードが最終的です。
synchronized: すべての同期操作は 1. アトミック性と 2. 可視性を保証する必要があるため、同期されたブロックで発生した変更はすぐにメイン メモリに書き戻されます
sleep: このメソッドは CPU 実行時間を放棄するだけで、ロックは解放されません。
問題分析
Q1: コードをコメントしてもプログラムが終了しないのはなぜですか?
A1: boolean is=true の変数値は前のスレッド (スレッド A と呼ばれます) によって独自の作業メモリにロードされるため、後続のスレッド (スレッド B と呼ばれます) が boolean is=false を変更した後は、ロードされない可能性があります。 (ただし、この質問では is=false を実行するとスレッドが終了するため、すぐにメインメモリに書き込まれます。) たとえすぐにメインメモリに書き込まれたとしても、スレッド A は書き込まれない可能性があります。すぐに作業メモリにロードされるので、プログラムは続行されます。終了しないでしょうか?これはほとんどの人が考えていることですが、実際には、JVM は現在のハードウェア レベルに合わせて大幅に最適化されており、基本的に作業メモリとメイン メモリのタイムリーな同期が大幅に保証されます。これは、揮発性メモリを使用するのと同等です。デフォルトでは。ただし、あくまで最大限の範囲で! CPU リソースが常に占有されている場合、作業メモリとメイン メモリ間の同期、つまり変数の可視性がそれほどタイムリーではなくなります。結論は後ほど検証します。
Q2: コード ブロック (1、2、3) のコメントを解除するとプログラムが終了するのはなぜですか?
A2: 行番号 1 と行番号 2 のコードには共通の特徴があり、すべて同期ロックがかかっているため、質問者が推測したように、メインメモリ上の変数値を強制的に同期して更新します。スレッドスタック? 、スリープメソッドもメインメモリ内の変数値をスレッドスタックにリフレッシュしますか?実際、synchronized は synchronized ブロック内の変数の可視性を保証するだけであり、変数は synchronized ブロック内にないため、これが原因ではないことは明らかです。次に、コード i; の後に次のコードを追加します:
for(int k=0;k
新しいオブジェクト();
}
もう一度実行すると、プログラムはすぐに終了します。なぜ?上記の A1 で、JVM の最適化を行ったとしても、CPU が常に占有されている場合、上記のプログラムが i をループで実行し続けるのと同じように、演算が CPU を占有するのと同じように、データの可視性が十分に保証されないことをすでに述べました。上記のコードを追加するとプログラムが停止するのはなぜですか?多数の new Object() 操作では、CPU は時間のかかる主な操作ではなくなり、実際に時間がかかるのはメモリの割り当てになるはずです (CPU の処理速度がメモリよりも明らかに速いため)そうでない場合、CPU レジスタは存在しません。) そのため、CPU がアイドル状態になった後、JVM 最適化ベンチマークに従い、できるだけ早くデータの可視性を確保し、それによって変数をメイン メモリから作業メモリに同期します。最終的にはプログラムの終了につながります。これが、sleep() メソッドに同期操作が含まれない理由です。ただし、sleep() メソッドは CPU を解放しますが、ロックは解放しないため、プログラムを終了することはできます。
以上がJava変数の可視性問題の分析例の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。