7

私はソースコード java.util.concurrent.atomic.AtomicIntegerを調べて、クラスによって提供されるアトミック操作によってどの程度のアトミック性が達成されているか調べました。java.util.concurrent.atomicパッケージで定義されたクラスで、どの程度のアトミック性が達成されますか?

public final int getAndIncrement() { 
    for (;;) { 
     int current = get(); 
     int next = current + 1; 
     if (compareAndSet(current, next)) 
      return current; 
    } 
} 

Iはループの無限の内部動作のシーケンスを書き込む目的を理解することができませんが、以下のように、例えば、 AtomicInteger.getAndIncrement()メソッド源です。 Java Memory Model(JMM)の特別な目的を果たしますか?わかりやすい説明を見つけてください。前もって感謝します。

+1

そのループでメソッドが呼び出されていて、そのメソッドの結果がループを解除する条件であることを無視しているようです。 Googleの "比較とスワップ" –

+1

これは古典的なユースケースです。 'goto'less言語では、無限ループを使います。 –

答えて

4

私が執筆の目的を理解することはできませんよループの無限ループ内での操作は です。

それは、私はそれが参考にcompareAndSetが何を理解し、どのようにそれがfalseを返すことを見つける無限ループに入っている理由を理解します。

Atomically sets the value to the given updated value if the current 
value == the expected value. 

Parameters: 
    expect - the expected value 
    update - the new value 
Returns: 
    true if successful. False return indicates that the actual value was not 
    equal to the expected value 

だからReturnsメッセージを読み、可能ということであるか尋ねますか?

2つのスレッドが同時に近い時刻にincrementAndGetを呼び出していて、両方とも入力して値current == 1を参照している場合。どちらのスレッドもスレッドローカルnext == 2を作成し、compareAndSetで設定しようとします。 1つのスレッドのみが文書化された通りに勝ち、失われたスレッドは再度試行する必要があります。

これはCASの動作方法です。失敗した場合は値を変更し、失敗した場合は再試行し、失敗した場合は続行します。

増分がではなく、であるため、単にフィールドをvolatileとして宣言するだけです。 JavaののcompareAndSetはCPU比較交換(CAS)の指示に基づいて

volatile int count = 0; 

public int incrementAndGet(){ 
    return ++count; //may return the same number more than once. 
} 
+1

ありがとうございます。 –

6

無限ループの中で一連の操作を記述する目的を理解できません。

このコードの目的は、volatileフィールドが​​ロックのオーバヘッドなしに適切更新されることを保証することです。この同じフィールドを更新するために多数のスレッドが競合している場合を除き、これを達成するためにはほとんど何回も回転します。

volatileキーワードは、可視性とメモリ同期の保証を提供しますが、複数の操作(テストと設定)によるアトミック操作を保証するものではありません。テスト中にvolatileフィールドを設定すると、複数のスレッドが同じ操作を同時に実行しようとすると競合条件が発生します。この場合、複数のスレッドが同時にAtomicIntegerをインクリメントしようとしている場合、増分の1つを欠落する可能性があります。並行コードはここvolatile intのみ、それはまだ3

  1. T1と等しい場合(たとえば)は、原子-INTとそれを取得4に更新されていることを確認する方法の基礎となるスピンループとcompareAndSetを使用しています0
  2. t2があるアトミック-INTを取得し、それが0
  3. t1は、それが0であることを確認するアトミックテストそれに
  4. t1に1を追加している、それは、格納1.
  5. t2はそれに1を加えます
  6. t2 原子的にが0であることをテストすると、それはではなく、であるため、スピンしてもう一度試してください。
  7. t2は、原子-INTを取得し、それが1
  8. T2で1
  9. それにT2 アトミックテストはそれが1であることを確認するために追加し、それ で、店舗2

Javaメモリモデル(JMM)で特別な目的を果たしますか。

いいえ、それはクラス及びメソッドの定義の目的を果たすとは、その目的を達成するために JMMとvolatile周りの言語の定義を使用します。JMMは、言語が、​​,volatileなどのキーワードと、複数のスレッドがキャッシュされたメモリと中央メモリと相互作用する方法を定義します。これは主に、オペレーティングシステムやハードウェアとのネイティブコードのやりとりに関するものであり、Javaコードについてはほとんどありません。

それは主に、いくつかのラッパーとのネイティブな方法であるUnsafeクラスに呼び出すことで、JMMに近づくcompareAndSet(...)方法です:

public final boolean compareAndSet(int expect, int update) { 
    return unsafe.compareAndSwapInt(this, valueOffset, expect, update); 
} 
+0

揮発性の私の理解によると、それは同期や明示的なロックを使用せずに可視性の目的を解決します。したがって、読み取り/書き込みの一貫性のある可視性のために、同期なしで揮発性を使用することができます。だから、なぜこの特別なループを同期のために使うのですか?ループと同期の関係についてもっと詳しく説明できれば、大きな助けになるでしょう。すぐ返事をありがとう。 –

+1

@VaibhavRaj - ループは同期とは関係ありません。 CAS操作が成功するまでループします。 –

+2

'volatile'は視認性に関するものです。 'AtomicInteger'は*ロックフリーの原子性*です。再試行なしには達成できません。無限ループ=再試行。 –

1

ので、このようなものは、私が説明したシナリオから安全ではないあるhttp://en.wikipedia.org/wiki/Compare-and-swapを参照してください。 メモリ位置の内容を指定された値と比較し、同じ場合にのみ、そのメモリ位置の内容を指定された新しい値に変更します。

incrementAndGetの場合、現在の値を読み込み、compareAndSet(current, current + 1)を呼び出します。 falseを返すと、別のスレッドが干渉して現在の値を変更したことを意味します。つまり、試行が失敗し、成功するまでサイクル全体を繰り返す必要があります。

関連する問題