アトミックに別の値と交換できるタイプの参照を実装する方法はありますか?
Java では、AtomicReference
これをローカル変数と交換できますが、別の変数と交換することはできませんAtomicReference
。
できるよ:
AtomicReference r1 = new AtomicReference("hello");
AtomicReference r2 = new AtomicReference("world");
2 つの操作の組み合わせでそれらを交換します。
r1.set(r2.getAndSet(r1.get()));
しかし、これにより、両方に が含まれているという矛盾した状態になります"hello"
。また、それらをアトミックに交換できたとしても、(ペアとして) アトミックに読み取ることはできませんでした。
私ができるようにしたいのは:
PairableAtomicReference r1 = new PairableAtomicReference("hello");
PairableAtomicReference r2 = new PairableAtomicReference("world");
AtomicRefPair rp = new AtomicRefPair(r1, r2);
それから
Object[] oldVal, newVal;
do {
oldVal = rp.get();
newVal = new Object[] {oldVal[1], oldVal[0]};
} while (! rp.compareAndSet(oldVal, newVal));
値を交換し、別のスレッドで:
AtomicRefPair otherRP = new AtomicRefPair(r1, r2);
System.out.println(Arrays.toString(otherRP.get()));
[hello, world]
出力が または のいずれかになることを確認して[world, hello]
ください。
ノート:
r1
この操作ではとr2
がペアになっていますが、別のスレッドが独立してペアになる可能性があります (たとえばr1
、別のスレッドと) (残念ながら、このソリューションr3
を使用できないことを意味します)。- これらの参照は数十万になるため、グローバル
ReentrantLock
が大きなボトルネックになります。 rp
必ずしもスレッド間で共有されるとotherRP
は限らないため、単純にロックするだけでは機能しません。それらはインターンされる可能性がありますが、インターンプールには独自の同期が必要であり、これが別のボトルネックになります。- ここでは 2 つの参照のグループしか作成していませんが、3 つ以上をグループ化する機能はおまけです。
のロックフリーバージョンを実装することは可能AtomicRefPair
ですか? そうではないという予感がありますが、そうでない場合は、その理由を説明する記事がどこかにあるのではないでしょうか?