32

最近、チュートリアルを読んでいたところ、次のようなステートメントに出くわしました..

「Java 言語仕様では、変数の読み取りまたは書き込みがアトミック操作であることを保証しています (変数が or 型でない限り) 。longor型の操作変数は、キーワードで宣言されている場合にのみアトミックです。」doublelongdoublevolatile

AtomicIntegerまたは、アトミックな、 、などのAtomicLongメソッドを提供します。getAndDecrement()getAndIncrement()getAndSet()

上記のステートメントと少し混乱しました..またはクラスをいつ使用するかを明確にしてください。 AtomicIntegerAtomicLong

4

6 に答える 6

59

a = 28(でaあることで)行うことintは、アトミック操作です。ただしa++、a の値の読み取り、インクリメント、および結果の a への書き込みが必要なため、実行はアトミック操作ではありません。その結果、a++スレッド セーフ カウンターを実装していた場合、2 つのスレッドが値を同時に読み取り (たとえば 26)、インクリメントと書き込みの両方を同時に行い、結果として 28 ではなく 27 になる可能性があります。 .

AtomicInteger は、リストしたようなアトミック操作を提供することで、この問題を解決します。私の例では、たとえば、incrementAndGet()最終値が 27 ではなく 28 であることを保証するものを使用します。

于 2013-05-24T07:09:05.287 に答える
12

アトミックとは、その間に何かが発生する可能性なしに操作が完了することを意味します。例えば。AtomicInteger の getAndDecrement() は、変数が返され、同時にデクリメントされることを保証します。

アトミック操作でない場合、値がデクリメントされ (例: 3 から 2)、別のスレッドによって変更され (例: 2 から 5 に変更)、5 として返される可能性があります。

于 2013-05-24T07:09:00.847 に答える
4

変数を読み取り、読み取った値に応じて結果を書き込む必要があるAtomicInteger場合は、 が必要です。たとえば、読み取り(例) と書き込み(例) です。その間、1 つのスレッドが中断される可能性があり、他の 3 つのスレッドもインクリメントされます。戻ると、実際には値がありますが、スレッドは事前に読み取った内容に基づいて を書き込みます。i++i3i+14ii64

AtomicInteger.getAndIncrement中断されないため、常に適切にインクリメントされます。さらに、結果は常にメモリにフラッシュされますが、不揮発性iはメモリにフラッシュされない場合があります。この場合、他のスレッドは変更を認識さえしない可能性があります。

于 2013-05-24T07:14:44.040 に答える
1

変数を変更するときは、操作の原子性が必要です。実行int a = 10;はアトミック操作ですが、問題を引き起こす操作ではありません。操作を与える問題は、通常、などのようなものを変更することa++ですa = a + 2;

Java 仕様では、「読み取り」と「書き込み」がそれらの組み合わせではなく、アトミック操作であることを保証しています。そのため、「読み取り、1 を追加し、結果を書き戻す」操作は、仕様に従ってアトミックではありません。このような操作は複合操作と呼ばれ、通常、コードでの使用のコンテキストでアトミックである必要があります。

アトミック型は、この問題の解決に役立ちます。アトミック型で incrementAndget() を使用すると、「読み取り、1 を追加し、結果を書き戻し、新しい結果を読み取る」ことが、スレッド セーフのコンテキストで単一のアトミック操作になります。

お役に立てれば。ちなみに、並行性とスレッドの基本に関するこの記事( http://walivi.wordpress.com/2013/08/24/concurrency-in-java-a-beginners-introduction/ ) を読む必要があります。それはそのようなことを美しく説明します。

于 2013-12-02T11:09:15.133 に答える