31

volatileは、可視性をAtomicInteger可能にし、原子性を可能にすることを知っています。それで、揮発性を使用する場合AtomicInteger、それは私がこれ以上同期メカニズムを使用する必要がないことを意味しますか?

例えば。

class A {

    private volatile AtomicInteger count;

    void someMethod(){
        // do something
        if(count.get() < 10) {
            count.incrementAndGet();
        }
}

これはスレッドセーフですか?

4

5 に答える 5

64

私はそれがAtomic*実際に原子性とボラティリティの両方を与えると信じています。したがって、(たとえば)に電話をかけると、最新のAtomicInteger.get()を取得することが保証されます。これはパッケージドキュメントに記載されています:java.util.concurrent.atomic

アトミックのアクセスと更新のメモリー効果は、Java™言語仕様のセクション17.4に記載されているように、一般に揮発性物質の規則に従います。

  • getには、揮発性変数を読み取るメモリ効果があります。
  • setには、揮発性変数の書き込み(割り当て)のメモリ効果があります。
  • lazySetには、揮発性変数の書き込み(割り当て)のメモリ効果があります。ただし、通常の不揮発性書き込みでは並べ替えの制約を課さない後続の(前ではない)メモリアクションで並べ替えることができます。他の使用状況の中でも、ガベージコレクションのために、ガベージコレクションのために、二度とアクセスされない参照をnullにするときに>--lazySetが適用される場合があります。
  • weakCompareAndSetは、変数をアトミックに読み取りおよび条件付きで書き込みますが、発生前の順序付けは作成しないため、weakCompareAndSetのターゲット以外の変数の前後の読み取りおよび書き込みに関して保証はありません。
  • compareAndSetと、getAndIncrementなどの他のすべての読み取りおよび更新操作には、揮発性変数の読み取りと書き込みの両方のメモリ効果があります。

今あなたが持っているなら

volatile AtomicInteger count;

このvolatile部分は、各スレッドが最新のAtomicInteger参照を使用することを意味し、それがそのオブジェクトの最新の値AtomicInteger表示されることを意味します。

これが必要になることは一般的ではありません(IME)。通常count、別のオブジェクトを参照するために再割り当てすることはないためです。代わりに、次のようになります。

private final AtomicInteger count = new AtomicInteger();

その時点で、それがfinal変数であるという事実は、すべてのスレッドが同じオブジェクトを処理することを意味します-そしてそれがオブジェクトであるという事実Atomic*は、それらがそのオブジェクト内の最新の値を見るということを意味します。

于 2013-01-15T13:19:07.693 に答える
6

シングルスレッドモードとマルチスレッドモードで同じ結果が得られるとスレッドセーフを定義した場合、それはスレッドセーフではありません。シングルスレッドモードでは、カウントが10を超えることはありませんが、マルチスレッドモードではカウントできます。

問題はそれgetであり、incrementAndGetアトミックですが、ifそうではありません。非アトミック操作はいつでも一時停止できることに注意してください。例えば:

  1. count = 9現在。
  2. スレッドAが実行され、そこでif(count.get() <10)取得trueおよび停止されます。
  3. スレッドBも実行if(count.get() <10)されて取得trueされるため、実行count.incrementAndGet()されて終了します。今count = 10
  4. スレッドAが再開して実行されますがcount.incrementAndGet()count = 11これはシングルスレッドモードでは発生しません。

遅いものを使用せずにスレッドセーフにしたい場合synchronizedは、代わりにこの実装を試してください。

class A{

final AtomicInteger count;

void someMethod(){
// do something
  if(count.getAndIncrement() <10){
      // safe now
  } else count.getAndDecrement(); // rollback so this thread did nothing to count
}
于 2014-08-30T06:45:17.230 に答える
2

元のセマンティクスを維持し、複数のスレッドをサポートするには、次のようにします。

public class A {

    private AtomicInteger count = new AtomicInteger(0);

    public void someMethod() {

        int i = count.get();
        while (i < 10 && !count.compareAndSet(i, i + 1)) {
            i = count.get();
        }

    }

}

これにより、カウントが10に達するスレッドを回避できます。

于 2014-12-02T13:03:35.460 に答える
1

答えはこのコードにあります

http://grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/6-b14/java/util/concurrent/atomic/AtomicInteger.java

AtomicIntegerのソースコードです。値は揮発性です。したがって、AtomicIntegerは内部でVolatileを使用します。

于 2014-11-23T07:05:51.057 に答える
0

質問には2つの質問があるため、質問には2つの部分で答えることができます。

1)アトミック変数に関するOracleのチュートリアルドキュメントを参照してください: https ://docs.oracle.com/javase/tutorial/essential/concurrency/atomicvars.html

java.util.concurrent.atomicパッケージは、単一変数に対するアトミック操作をサポートするクラスを定義します。すべてのクラスには、揮発性変数の読み取りと書き込みのように機能するgetメソッドとsetメソッドがあります。つまり、セットには、同じ変数に対する後続のgetとの発生前の関係があります。アトミックcompareAndSetメソッドには、整数アトミック変数に適用される単純なアトミック算術メソッドと同様に、これらのメモリ整合性機能もあります。

したがって、ここで他の回答が述べているように、アトミック整数は内部で揮発性を使用します。したがって、アトミック整数を揮発性にすることには意味がありません。メソッドを同期する必要があります。

Udemyに関するJohnPurcellの無料ビデオをご覧ください。ここでは、複数のスレッドが変更しようとしているときにvolatileキーワードが失敗することを示しています。シンプルで美しい例。 https://www.udemy.com/course/java-multithreading/learn/lecture/108950#overview

Johnの例の揮発性カウンターをアトミック変数に変更すると、彼のチュートリアルで行ったように、sunchronizedキーワードを使用せずに彼のコードが成功することが保証されます。

2) Coming to your code : Say thread 1 kicks into action and "someMethod" does a get and checks for size. It is possible that before getAndIncrement executes(say, by thread 1) , another thread (say thread 2)kicks in and increases the count to 10, and gets out; after which, your thread 1 will resume and increase count to 11. This is erroneous output. This is because your "someMethod" is not protected in anyway from synhronization problems. I would still recommend you to watch john purcell's videos to see where volatile fails , so that you have a better understanding of the keyword volatile. Replace it with atomicinteger in his example and see the magic.

于 2019-08-29T16:13:46.763 に答える