データベース呼び出しの結果への参照を設定するために AtomicReference.compareAndSet を使用することは適切ですか? のような質問への回答を探しています。しかし、異なる要件があります。
目標は、ObjectWithSideEffectConstructor
副作用の重複を避けるために、インスタンスを 1 回だけ作成することです。構築は で行う必要がありsetUp()
ます。複数のスレッドが を呼び出しますsetUp()
。同様にtearDown()
、オブジェクトからリソースを回収するための がありますが、ここでは省略されています。質問: 目標を達成するためのベスト プラクティスは何ですか?
AtomicReference
副作用として、コンストラクターが最初に実行されるため、単に使用するだけでは十分ではありません。
private static AtomicReference<ObjectWithSideEffectConstructor> ref =
new AtomicReference<ObjectWithSideEffectConstructor>()
void setUp() {
ref.compareAndSet(null, new ObjectWithSideEffectConstructor());
}
データベース呼び出しの結果への参照を設定するために AtomicReference.compareAndSet を使用することは適切ですか?からの回答を使用します。volatile
同期が取れていないため、機能しません。複数のスレッドが入るウィンドウがありますif
。
private static volatile ObjectWithSideEffectConstructor obj;
void setUp() {
if (obj == null) obj = new ObjectWithSideEffectConstructor();
}
簡単な修正は
private static ObjectWithSideEffectConstructor obj;
private static final Object monitor = new Object();
void setUp() {
synchronized (monitor) {
if (obj == null) obj = new ObjectWithSideEffectConstructor();
}
}
同様に、揮発性モニターを使用する DCL を使用すると、読み取りパフォーマンスが向上する場合があります。ただし、どちらもある程度の同期が必要なため、パフォーマンスが低下することが予想されます。
も使えますFutureTask
。オブジェクトが作成されると、後続FutureTask.get()
はブロックせずに戻るため、より効率的です。しかし、それは間違いなく よりもはるかに複雑ですsynchronized
。
private static final AtomicReference<FutureTask<ObjectWithSideEffectConstructor>> ref =
new AtomicReference<FutureTask<ObjectWithSideEffectConstructor>>();
void setUp() {
final FutureTask<ObjectWithSideEffectConstructor> future =
new FutureTask<ObjectWithSideEffectConstructor>(
new Callable<ObjectWithSideEffectConstructor>() {
@Override
public ObjectWithSideEffectConstructor call() throws InterruptedException {
return new ObjectWithSideEffectConstructor();
}
}
);
if (ref.compareAndSet(null, future)) future.run();
ref.get().get();
}
提案をありがとう。