web-dev-qa-db-ja.com

AtomicBooleanのgetAndSetとcompareAndSetの違い

スレッドのタイトルは自明である必要があります...私はAtomicBooleanクラスからの以下の方法の指定の間で少し混乱しています:

  • Java.util.concurrent.atomic.AtomicBoolean#compareAndSet
  • Java.util.concurrent.atomic.AtomicBoolean#getAndSet

私の強要は、if条件でブール句として使用した場合、どちらも同じ動作になるということです。

public class Test {
  private AtomicBoolean flag = AtomicBoolean(false);

  public void processSomeAction() {
    if (flag.getAndSet(false)) { // Shouldn't this be similar to flag.compareAndSet(false)
      // process some action
    }
  }
  //...
  private void internalMutatorMethod() {
    // do some staff then update the atomic flag
    flas.set(true);
  }
}

現在のフラグ値を取得して自動的に更新したい場合、両方の方法で同じ動作が発生するのではないでしょうか。

内部の違いが見当たらない場合は、それぞれをいつどのように使用するかについての説明をいただければ幸いです。

17
tmarwen

ドキュメント はかなり明確です。

  • getAndSet->「指定された値に原子的に設定し、前の値を返します。」
  • compareAndSet-> "現在の値==期待値の場合、値を指定された更新値に原子的に設定します。"

当然のことながら、compareAndSetは2つの引数を取ります。

あなたの特定のケースでは:

  • if (flag.getAndSet(false))は、前の値がflagの場合にのみ、falsetrueに設定します。
  • これはif (flag.compareAndSet(true, false))と同等です
17
Mena

あなたはより良い理解のためにコードを見ることができます:

public final boolean getAndSet(boolean newValue) {
    for (;;) {
        boolean current = get();
        if (compareAndSet(current, newValue))
            return current;
    }
}

getAndSetでは、古い値をget()してからその値を変更しようとするまでの間にブール値が変更された場合、compareAndSetはその値を変更しません値。したがって、getAndSetは、ブール値が新しい値に設定されるまで、ループでcompareAndSetを呼び出します。

あなたのコード例について:

flag.getAndSet(false)は、AtomicBooleanの古い値を返します。一方、flag.compareAndSet(x,false)(2つの引数があることに注意)は、AtomicBooleanが変更されたかどうかを返します。つまり、AtomicBooleanの古い値がxであったかどうかを返します。

7
Eran

実装を確認したところ、次のことがわかりました

public final boolean getAndSet(boolean newValue) {
    for (;;) {
        boolean current = get();
        if (compareAndSet(current, newValue))
            return current;
    }
}

また、javadocをチェックするとき、compareAndSetは比較に合格した場合にのみ値を設定し、getAndSetは単に値を設定して前の値を返します。

0
sodik

スレッドは少し古いですが、getAndSetがcompareAndSetよりも効率的であるとは誰も言及していません。 CASは非常にコストのかかる命令です(すべてのCPUアーキテクチャ上で、JVMはここでは問題になりません)。したがって、それらは実際には同等ではありません。

したがって、OPに関しては、両方のメソッドが同じ動作を生成しますが、同じパフォーマンスは得られません。可能であればgetAndSetを使用してください。

0
MappaM