2016-04-08 11 views
0

われわれが知っているように、シンプルなダブルチェックには、JVMが使用するコマンドのために問題があります。ダブルチェック付きのJavaシングルトン

class MyClass { 

    private String Name; 

    private static Object o = new Object(); 
    private static MyClass Instance=null; 

    private MyClass(){ 
     //Thread.sleep(1000); 
     Name="test case"; 
    } 
    public static MyClass GetInstance(){ 
     if(Instance==null){ 
      synchronized(o){ 
       if(Instance==null){ 
        Instance = new MyClass(); 
        //MyClass obj = new MyClass(); 
        //Instance = obj; 
       } 
      } 
     } 
     return Instance; 
    } 
} 

私がInstance = new MyClass();をコメント行に置き換えた場合。これは機能しますか?

+0

いいえ、ちょうど['volatile']にします(https://en.wikipedia.org/wiki/)。 Double-checked_locking#Usage_in_Java)。 –

+0

MyClass obj = new MyClass();新しいインスタンスが返され、インスタンスにオブジェクトが割り当てられます。これが機能しないのはなぜですか?私は本当に理由を知らないのです。 –

+0

'volatile'を使って正しく実装しても、ダブルチェックロックはほとんどありません。レイジーインスタンス化されたシングルトンは、[オンデマンドホルダーイディオムの初期化](https://en.wikipedia.org/wiki/Initialization-on-demand_holder_idiom)を使用する必要があります。 – Radiodef

答えて

1

これは機能しません。スレッドAとスレッドBを考えてください。スレッドAはInstancenullであるとみなし、MyClassのインスタンスを作成するためにsynchronizedブロックに入り、フィールドInstanceに割り当てます。

Javaメモリモデルの規則のため、再順序付けが行われ、部分的に初期化されたオブジェクトまたは初期化されていないオブジェクトMyClassInstanceに割り当てることができます。今度はスレッドBが同じGetInstanceメソッドに入り、Instanceがヌルではないことを確認し、スレッドAと同じモニターに同期ブロックを入力してから、完全に初期化されていないオブジェクトを返します。

初期化を2行のコードに分割するか1行にするかどうかは、この問題の意味がありません。どちらの場合でも並べ替えが発生する可能性があります。 Javaコンパイラは、両方のバージョンのコードを同じバイトコードに合法的にコンパイルすることができます(ただし、現在のコンパイラでは使用できません)。

+0

コンパイラはコードを最適化することができます。その結果、違いはありません。どうもありがとう 。 –

関連する問題