1.揮発性を使用する理由
では、Java仮想マシンの-depth理解 JVMメモリモデルを述べました。マルチスレッド操作では、スレッド間の共通変数の転送は、メインメモリを介して実現する必要があります。通常の状況では、各スレッドはメインメモリ内の変数を取得し、それを独自の作業メモリに配置してから、変数値の読み取りと書き込みを行います。スレッドが終了したら、変数をメインメモリに配置します。異なるスレッド間の変数には直接アクセスできません。したがって、スレッドは同じ変数の他のスレッドによって変更された値をタイムリーに取得できません。変数は表示されません。したがって、スレッドによって書き込まれた変数が他のスレッドから確実に見えるようにするには、同期を追加する必要があります。
2.揮発性物質の使用
変更されたクラス変数:揮発性ブールb = true;
アドバンテージ
1.スレッド間の変数の可視性が
volatileによって変更されていることを確認します。スレッドがこの変数の値を変更すると、volatileは、新しい値をメインメモリにすぐに同期し、使用する直前にメインメモリから更新できるようにします。 。変数は、レジスタや他のプロセッサからは見えない場所にはキャッシュされません。
2.命令の並べ替えの最適化
割り当てが禁止された後、追加の「load addl $ 0x0、(%esp)」操作が実行されます。この操作はメモリバリアと同等です(命令の並べ替え中、メモリバリアの前に次の命令を並べ替えることはできません)場所)。
短所
操作の原子性は保証されません。
volatile int count = 0;
/*synchronized*/ void m(){
for(int i = 0; i < 10000; i++){
System.out.println(Thread.currentThread().getName() + " - " + i);
count++;
}
}
public static void main(String[] args) {
final Test_10 t = new Test_10();
List<Thread> threads = new ArrayList<>();
for(int i = 0; i < 10; i++){
threads.add(new Thread(new Runnable() {
@Override
public void run() {
t.m();
}
}));
}
for(Thread thread : threads){
thread.start();
}
for(Thread thread : threads){
try {
//join() 等线程执行结束,主线程再执行。
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println(t.count);
}
予想される結果は100,000ですが、実際には100,000未満になります。
count ++;アトミック操作ではなく分割できます。非アトミック操作にはスレッドセーフの問題があります。
解決策:ロックまたはアトミック操作に変更します。
つまり、
1)同期(this){
count ++;
}
2)
AtomicInteger count = new AtomicInteger(0);
count.incrementAndGet();
incrementAndGet()はアトミック操作です。
3.使用シナリオ
1.変数の書き込み操作は変数の現在の値に依存しないか、単一のスレッドのみ
が変数の値を更新することを確認できます2.変数は他の状態変数と一緒に不変性条件に含まれません
3. 変数にアクセスする場合は不要ですロックする