私は、グローバル変数を持っています
volatile i = 0;
そして二つのスレッド。それぞれ、次のことを行います。
i++;
System.out.print(i);
私は、以下の組み合わせを受けます。12、21、22。
私は11(揮発性禁止し、iのキャッシング)を取得しない理由を私は理解し、私はまた、12と22を理解しています。
私は理解していない何がそれが21を得ることが可能である方法ですか?
あなたはこの組み合わせを得ることができますどのように唯一可能な方法は、プリントが後で増分に最初でなければならなかったことをそのスレッドでi
0から1にして、キャッシュされましたi==1
。次いで、他のスレッドがインクリメントi
1から2へ、次いで2.次いで、最初のスレッドがキャッシュを印刷する印刷しますi==1
。しかし、私はその考えvolatile
不許可のキャッシングを。
編集:私は一度11を持っ万回のコードを実行した後。追加volatile
するにはi
、すべての可能な組み合わせを変更しません。
キャッシング揮発性は禁止:markspaceは正しいですi
が、i++
アトミックではありません。この手段i
はまだ一種の取得は、増分の間にレジスタに「キャッシュされました」。
r1 = i
//if i changes here r1 does not change
r1 = r1 + 1
i = r1
これは、11はまだ可能である理由です。PrintStreamsが同期されていないので、21が発生する(カロルDowbeckiの回答を参照してください)
残念ながら、++
アトミック操作ではありません。かかわらず、volatile
JVMは、インクリメントを読み、その後別の操作として書き込むためのキャッシュを許可しない、それが許可されています。このように、あなただけの実装しようとしている概念は実行可能ではありません。あなたは使用する必要がありsynchronized
、そのミューテックス、またはのような使用のために何かAtomicInteger
アトミックインクリメント動作を提供しています。