遅延初期化と、作成がスレッドセーフである必要のないオブジェクトの格納用に設計されたクラスがあります。コードは次のとおりです。
class SyncTest {
private static final Object NOT_INITIALIZED = new Object();
private Object object;
/**
* It's guaranteed by outer code that creation of this object is thread safe
* */
public SyncTest() {
object = NOT_INITIALIZED;
}
public Object getObject() {
if (object == NOT_INITIALIZED) {
synchronized (NOT_INITIALIZED) {
if (object == NOT_INITIALIZED) {
final Object tmpRef = createObject();
object = tmpRef;
}
}
}
return object;
}
/**
* Creates some object which initialization is not thread safe
* @return required object or NOT_INITIALIZED
* */
private Object createObject() {
//do some work here
}
}
ここで、final
変数tmpRef
は、作成されたオブジェクトを格納してから、チェックされた変数に割り当てるために使用されますobject
。これはテストでは機能しますが、確実に正しいとは言えず、コンパイラによって最適化されません。このアプローチを使用できますか、またはobject
フィールドを次のように宣言する必要がありますvolatile
か?
また、ラッパー クラスを使用したバリアントは、行が
final Object tmpRef = createObject();
これに置き換える必要があります:
Object tmpRef = new FinalWrapper(createObject()).getVal();
ラッパー クラスは次のようになります。
private class FinalWrapper {
private final Object val;
public FinalWrapper(Object val) {
this.val = val;
}
public Object getVal() {
return val;
}
}
この例のいくつかは、マルチスレッド環境で安全に使用できますか (特に final ローカル フィールドを持つバリアント)?