このコードは、Javaのダブルチェックロックの問題を解決していますか?
-
12-11-2019 - |
質問
このコードは、Javaの二重チェックロック問題を解決しますか?
public class DBAccessService() {
private static DBAccessService INSTANCE;
private DBAccessService() {}
public static DBAccessService getInstance() {
if (INSTANCE != null) {
return INSTANCE;
}
return createInstance();
}
private static synchronized DBAccessService createInstance() {
if (INSTANCE != null) {
return INSTANCE;
}
DBAccessService instance = new DBAccessService();
INSTANCE = instance;
return INSTANCE;
}
}
.
注意を払うための2つの側面があります:
-
getInstance()
はではなく同期されているので、インスタンスが初期化された後、同期のコストはありません -
createInstance()
は同期だから、問題は次のとおりです。このコードには問題がありますか?それは合法的で常にスレッドセーフ?
解決
この質問を解決するための Java並行性(基本的にjava.utilを書いたチームによって書かれた.concurrent図書館遅延初期化ホルダークラスIDIOM (16.6ページのコピーの中で、 16.7)
@ThreadSafe
public class DBAccessServiceFactory {
private static class ResourceHolder {
public static DBAccessService INSTANCE = new DBAccessService();
}
public static DBAccessService getResource() {
return ResourceHolder.INSTANCE;
}
}
.
これは常に合法でスレッドセーフです。私は専門家ではないので、これはあなたのコードよりも優れていると言うことができません。しかし、それがDoug LeaとJoshua Blochによって推奨されるパターンであることを考えると、私はあなたが常にあなたまたは私が発明しました、そして私はそれが間違いを作るのがとても簡単であるので(この質問に対する間違った回答の数によって示されるように) )
彼らが言う揮発性の問題に関連しています:
JMM(Java 5.0以降)の変更は、リソースが揮発性にされている場合はDCLが機能することができました...しかし、LAZY初期化ホルダーのIDIOMは同じ利点を提供し、理解しやすいです。
他のヒント
INSTANCE
をvolatile
として宣言する必要があります。
private static volatile DBAccessService INSTANCE;
.
注Java 5以降でのみ機能します。「ダブルチェックロックは壊れています」宣言。
はうまく見えます。 2つのスレッド呼び出し()とインスタンスが発信されていない場合は、createInstance()を続行することができるスレッドが1つだけであり、2番目のスレッドはすでにインスタンスがNULLではないことがわかります。
唯一のものは、例えばvolatile
キーワードです。それ以外の場合、Javaはそれをキャッシュできます。