質問

次のクラスがあるとします

public class AccessStatistics {
  private final int noPages, noErrors;
  public AccessStatistics(int noPages, int noErrors) {
    this.noPages = noPages;
    this.noErrors = noErrors;
  }
  public int getNoPages() { return noPages; }
  public int getNoErrors() { return noErrors; }
}

次のコードを実行すると、

private AtomicReference<AccessStatistics> stats =
  new AtomicReference<AccessStatistics>(new AccessStatistics(0, 0));

public void incrementPageCount(boolean wasError) {
  AccessStatistics prev, newValue;
  do {
    prev = stats.get();
    int noPages = prev.getNoPages() + 1;
    int noErrors = prev.getNoErrors;
    if (wasError) {
      noErrors++;
    }
    newValue = new AccessStatistics(noPages, noErrors);
  } while (!stats.compareAndSet(prev, newValue));
}

最後の行で while (!stats.compareAndSet(prev, newValue)) はどうですか compareAndSet 方法 平等を判断するprev そして newValue?それは AccessStatistics 実装するために必要なクラス equals() 方法?そうでない場合は、なぜですか?javadoc には次のように記載されています AtomicReference.compareAndSet

現在の値 == 期待値である場合、値を指定された更新された値にアトミックに設定します。

...しかし、この主張は非常に一般的であるように見え、私がAtomicReferenceで読んだチュートリアルでは、AtomicReferenceでラップされたクラスにequals()を実装することは決して示唆されていません。

AtomicReference でラップされたクラスが、equals() を実装する必要がある場合、より複雑なオブジェクトの場合 AccessStatistics AtomicReference を使用せず、オブジェクトを更新するメソッドを同期した方が速いのではないかと考えています。

役に立ちましたか?

解決

== 演算子を使用したかのように、参照を正確に比較します。つまり、参照は同じインスタンスを指している必要があります。Object.equals() は使用されません。

他のヒント

実際、そうなります ない prev と newValue を比較してください。

代わりに、stats 内に格納されている値を prev と比較し、それらが同じである場合にのみ、stats 内に格納されている値を newValue に更新します。上で述べたように、これを行うには等号演算子 (==) を使用します。これは、prev が stats に格納されているのと同じオブジェクトを指している場合にのみ、stats が更新されることを意味します。

これはオブジェクト参照の同等性 (別名 ==) をチェックするだけなので、AtomicReference が保持するオブジェクト参照が参照を取得した後に変更された場合、参照は変更されないため、最初からやり直す必要があります。

以下は AtomicReference のソース コードの一部です。AtomicReference はオブジェクト参照を指します。この参照は、以下に示す AtomicReference インスタンスの揮発性メンバー変数です。

private volatile V value;

get() は単に変数の最新の値を返します (volatile が「前に起こる」方法で行うように)。

public final V get()

以下は AtomicReference の最も重要なメソッドです。

public final boolean  compareAndSet(V expect, V update) {
        return unsafe.compareAndSwapObject(this, valueOffset, expect, update);
}

CompareAndSet(expect,update) メソッドは、Java の安全でないクラスの CompareAndSwapObject() メソッドを呼び出します。この unsafe メソッド呼び出しはネイティブ呼び出しを呼び出し、プロセッサへの単一の命令を呼び出します。「expect」と「update」はそれぞれオブジェクトを参照します。

同じオブジェクトを参照する AtomicReference インスタンス メンバー変数 "value" が "expect" によって参照される場合に限り、このインスタンス変数には "update" が割り当てられ、"true" が返されます。それ以外の場合は false が返されます。すべてはアトミックに行われます。他のスレッドがその間をインターセプトすることはできません。これは単一プロセッサの操作 (現代のコンピューター アーキテクチャの魔法) であるため、多くの場合、同期ブロックを使用するよりも高速です。ただし、複数の変数をアトミックに更新する必要がある場合、AtomicReference は役に立たないことに注意してください。

Eclipse で実行できる本格的な実行コードを追加したいと考えています。そうすれば多くの混乱が解消されるでしょう。ここでは 22 人のユーザー (MyTh スレッド) が 20 席を予約しようとしています。以下にコード スニペットとその後に完全なコードを示します。

22 人のユーザーが 20 席を予約しようとしているコード スニペット。

for (int i = 0; i < 20; i++) {// 20 seats
            seats.add(new AtomicReference<Integer>());
        }
        Thread[] ths = new Thread[22];// 22 users
        for (int i = 0; i < ths.length; i++) {
            ths[i] = new MyTh(seats, i);
            ths[i].start();
        }

以下は、小さくて簡潔な実行中の完全なコードを確認したい人のための github リンクです。https://github.com/sankar4git/atomicReference/blob/master/Solution.java

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top