2011-12-06 6 views
2

Googleのアプリで「Double-checked locking」の1つのコードが発生している可能性があります。私が行っているのと同様のサンプルコードを書いています。このコードは二重チェックロックされていますか?

これはどのようにダブルチェックロックが発生する可能性があります誰が見ることができますか?それとも安全ですか?

class Foo { 
    private Helper helper = null; 
    public Helper getHelper() { 
     Helper result; 
     synchronized(this) { 
      result = helper; 
     } 

     if (helper == null) { 
      synchronized(this) { 
       if (helper == null) { 
        helper = new Helper(); 
       } 
      } 
     } 
     return helper; 
    } 
} 

wikiから借りたベースコード。

+0

はい、これはダブルチェックロックです –

+0

なぜ 'result'を宣言して使用しないのですか? –

+1

@Aishwar、リンクしているウィキペディアのページ、特に「揮発性」については、それを使ってください(またはDCLを使わないでください)。 – Bruno

答えて

3

ダブルチェックロックのポイントは、高速パス(オブジェクトをインスタンス化する必要がない場合)が同期されていない点です。だからあなたが持っているのはダブルチェックロックではありません。

壊れた二重チェックロックを取得するには、最初に同期されたブロックを削除する必要があります。その後、それを修正するにはhelperを揮発性にする必要があります。

+0

これは最善の答えです。 – bestsss

+0

ありがとうございます。これは私の質問に答える。上記のコードが二重チェックロックではない理由を説明します。 – Aishwar

6

それは必要以上に複雑だ、DCLを行うための最も簡単な「安全」な方法はそうのようなものです:

class Foo { 
    private volatile Helper helper = null; 
    private final Object mutex = new Object(); 
    public Helper getHelper() { 
    if (helper == null) { 
     synchronized(mutex) { 
      if (helper == null) { 
       helper = new Helper(); 
      } 
     } 
    } 
    return helper; 
    } 
} 

ここでのキーポイントはいる:我々はヘルパー期待する「幸せ」の場合

  • すでに割り当てられているので、同期ブロックに入る必要なしに返すことができます。
  • ヘルパーはいつでも任意のスレッドがヘルパーを読み書きできることをコンパイラに知らせるために揮発性とマークされています。読み書きは順序が変更されないことが重要です。
  • thisインスタンスで同期する別のコード領域の場合に、同期ブロックはプライベート最終変数を使用してオンに同期し、潜在的なパフォーマンスの低下を回避します。
+2

ローカル変数にヘルパーを割り当てる必要があります。 – bestsss

0

この部分は、標準のダブルチェックロックされています

if (helper == null) { 
    synchronized(this) { 
     if (helper == null) { 
      helper = new Helper(); 
     } 
    } 
} 

最初の部分は、ダブルチェックロック部分に何もしない無用の割り当てです:ヘルパーがnullの場合、それはとにかく実行され、場合それはとにかく実行されないではありません。それは完全に無効です。

+0

他のすべてのものは同じですが、それは間違っています。 –

+0

@Viruzzoここで私の理解は間違っているかもしれません。しかし、私はこれが起こることを想像しました。ヘルパーを割り当てている間、これにロックがあります。これにはgetHelper関数の始めに別のロックがあります。スレッド2で割り当てが行われているときにgetHelperがスレッド1で呼び出された場合、最初の同期ブロックはスレッド2の割り当てが完了するまでスレッド1の実行を保持します。したがって、ヘルパーの値は設定されている間は決してアクセスされません。 – Aishwar