2017-11-06 6 views
1

私はダブルチェックロックについてarticleを読んでいました。Double-Check Locking(DCL)とその修正方法

public class MyFactory { 
    private static final MyFactory instance; 

    static { 
     try { 
      instance = new MyFactory(); 
     } catch (IOException e) { 
      throw new RuntimeException("Darn, an error's occurred!", e); 
     } 
    } 

    public static MyFactory getInstance() { 
     return instance; 
    } 

    private MyFactory() throws IOException { 
     // read configuration files... 
    } 
} 

著者は言う:すべてのgetInstance()呼び出しで同期を避けるために、どのように提案方法の

public class MyFactory { 
    private static MyFactory instance; 

    public static synchronized MyFactory getInstance() { 
     if (instance == null) 
      instance = new MyFactory(); 
     return instance; 
    } 

    private MyFactory() {} 
} 

一つは、クラスローダを使用することです:次のように述べた問題がある」... JVMクラスが最初に参照されロードされたときに、この静的初期化コードが正確に1回呼び出されるようにします。私は完全に同意します。しかし、私は次のことを理解していません。「クラスローダーを使用するのは、一般的に私がレイジーな静的初期化を処理するのに望ましい方法です。

2番目のコードスニペットは遅延静的初期化ですか?

+0

まず、この問題の例は、メソッド全体が同期されているため、二重チェックロックを作成しません。私はあなたがここから最初に問題を理解しなければならないのではないかと心配しています。 https://www.javamex.com/tutorials/double_checked_locking.shtml –

+0

@LyjuIEdwinson最初のコードスニペットはこの文脈での問題です。引用:「...いくつかのプログラマーは、すべての読み込みでそれを使用するのを嫌っています同期化されたアクセスと "同期が遅い" "また、私が理解する限り、ダブルチェックロックもその解決策の1つです。 –

+1

より簡潔にするために、最初のコードスニペットは解決すべき問題です。 'getInstance()'が呼び出されるたびに同期が実行されるため、処理が遅くなります。 'getInstance()'のすべての呼び出しで同期を避ける方法の1つは、Double-checked Lockingのanti-patternを使うことです。別の方法は、2番目のコードスニペットを使用することです。 [article](https://www.javamex.com/tutorials/double_checked_locking_fixing.shtml)は、2番目のコードスニペットが遅延静的初期化であると主張しています。私はそれがなぜ怠惰な静的な初期化であるのか分かりません。 –

答えて

1

正確ではありません。 MyFactoryクラスがロードされたときに初期化されます。getInstance()が呼び出されたときではありません。メソッドが呼び出されたときにインスタンスを初期化する場合は、ホルダークラスを使用できます。

public class MyFactory { 
    private static final class Holder { 
     private static final MyFactory instance = new MyFactory(); 
    } 

    public static MyFactory getInstance() { 
     return Holder.instance; 
    } 
} 
2

これは怠惰ではありません。これは怠け者です(クラスローダーを使用しています)。

public class Singleton { 

    public static class SingletonHolder { 
     public static final Singleton HOLDER_INSTANCE = new Singleton(); 
    } 

    public static Singleton getInstance() { 
     return SingletonHolder.HOLDER_INSTANCE; 
    } 
} 
1

二重チェックロックは、火を放つようなプレイです。誰かがそれを間違えることができる多くの方法があります。

ダブルチェックロックイディオムの目的は、不要なsynchronizationを避けることです。したがって、最初のコードスニペットはカテゴリに収まりません。あなたが作成しているシングルトンがstaticであれば、2番目のコードスニペットに来

、その後、あなたは別のクラスではなく、同じクラスにstaticフィールドとしてシングルトンを定義することが可能なコンパクトなソリューションがあります。

class MyFactorySingleton { 
    static MyFactory singleton = new MyFactory(); 
} 

のJavaのこの意味は、フィールドが参照されるまで、フィールドが初期化されないことを保証し、そのフィールドは、そのフィールドを初期化から生じたすべての書き込みを見ることができますアクセスするスレッド。

しかし、その後JDK5とから、Javaはvolatile宣言された変数の

値はスレッドローカル をキャッシュされないことを言うvolatileセマンティクスをサポートし始めています。すべての読み込みと書き込みは、「メイン メモリ」にまっすぐに進みます。変数へのアクセスは、 同期ブロックに囲まれているかのように動作し、同期します。

ので、ダブルチェックを探しのためのいくつかの何愚か者の証拠の設計は、次のようになります

class MyFactory { 
    private volatile MyFactory instance = null; 

    public MyFactory getInstance() { 
    if(instance == null) { 
     synchronized(MyFactory.class) { 
      if(instance == null) { 
       instance = new MyFactory(); 
      } 
     } 
    } 
    return instance; 
    } 
} 

教授ジョシュア・ブロックと彼の共著者は、ダブルチェックロックは間違って行くことができる方法を説明しますこのarticleのこれを読む価値があります。

関連する問題