2012-02-29 9 views
10

これは十分な情報になると思いますので、ここで説明します。あなたがより多くの情報を必要とするならば、コメントにコメントがあります。Javaで同期を使用する場合

私は2つの内部クラスを持つクラスを持っています。内部クラスにはそれぞれ外部クラスのメソッドを呼び出す2つのメソッドがあります。だから、それは次のようになります。

public OuterClass { 
    private boolean outerMethodHasBeenCalled = false; 

    private void outerMethod() { 
     if(!outerMethodHasBeenCalled) { 
      // do stuff 
     } 

     outerMethodHasBeenCalled = true; 
    } 

    private FirstInnerClass { 
     public void someMethod() { 
      outerMethod(); 
     } 
    } 

    private SecondInnerClass { 
     public void someOtherMethod() { 
      outerMethod(); 
     } 
    } 
} 

それを注意することが重要です。

  • これは、Androidアプリのためです。 FirstInnerClassSecondInnerClassのインスタンスはJavaScriptインターフェイスとしてWebViewに渡されるため、特定の順序でいつでもsomeMethodsomeOtherMethodを呼び出すことができます。
  • 私は現在、同期されたキーワードなしで、既存のコードに問題があります。outerMethodはまったく同じ時刻に呼び出されます(ログメッセージを出力し、1000秒にタイムスタンプされます)。異なるオブジェクト。 outerMethodが呼び出されたときにouterMethodHasBeenCalledがまだ偽であるため、私のアプリは 'それは2回行う'ということになります。これは大丈夫ではありません、それはまさに私が防止しようとしていることです。私のアプリは、一度だけ、一度だけ「ものをする」べきです:初めてouterMethodが呼び出されます。
  • OuterClassの複数のインスタンスがあるように聞こえるかもしれませんが、それはOuterClassの1つのインスタンスであることを確かめてください。

outerMethodが初めて呼び出されたときだけ、私のアプリは「大切にする」ことが重要です(これは明らかです)。以降の呼び出しはすべて無視されます。どんな内部クラスがouterMethodを最初に呼び出すかは問題ではありません。

この場合、synchronizedキーワードを使用することは適切ですか?

答えて

19

うん、あなたは上記にレイアウトした内容を考えると、私はいいと思うが:

private synchronized void outerMethod() { 
... 
} 

注、これはouterMethod()が完了するまで、発信者のいずれかを遮断するの副作用を持つことになります。それが受け入れられるならば、冷たい。意図はouterMethod()内のコードを一度に実行されていることだけであるならば、それは最初の発信者がouterMethod()を実行している場合は延期されない第二の呼び出し元に対するOKですが、あなたは考えるかもしれません:

public OuterClass { 
    private AtomicBoolean outerMethodHasBeenCalled = new AtomicBoolean(); 

    private void outerMethod() { 
     if (outerMethodHasBeenCalled.compareAndSet(false, true)) { 
      // do stuff 
     } 
    } 
... 

JavaDoc for AtomicBooleanを参照してください(AndroidのJavaで利用可能であると仮定)。

+9

+1 AtomicBooleanのために、何か新しいことを学んだ:) – quaylar

7
あなたは同期ブロックに一度だけ実行したい outerMethod

ラップすべてが:

private void outerMethod() { 
    synchronized (this) { 
     if(!outerMethodHasBeenCalled) { 
      // do stuff 
     } 

     outerMethodHasBeenCalled = true; 
    } 
} 

そのように、メソッドが呼び出された最初の時間は、1つのスレッドのみで同期ブロックに入ることを許可されます時間。最初のコードはif文でコードを実行し、次にouterMethodHasBeenCalledtrueに設定します。他のスレッドは、それが真であることを確認し、ifコードをスキップします。

+0

他のスレッドが確実に変更を見ることができるように、フラグ 'volatile'を作る必要はありませんか?おそらくAtomicBooleanを使って安全な側にすることができます。 – Thilo

+1

@Thilo:フラグへのすべてのアクセスがsynchronizedブロックの中にある場合、 'volatile'を使う必要はありません。Javaメモリモデルにより、変更が確実に表示されます。 AtomicBooleanとvolatileは、完全に同期化されたブロックのコストを必要としたくない場合に便利ですが、使用するのが面倒です。 – Avi

+2

@Thilo outerMethodHasBeenCalledがアクセスされる唯一の場所がouterMethodにある場合、必要はありません。 synchronizedキーワードは、メモリ同期バリアを示します。 synchronizedキーワードのVM仕様を読んでください。ところで、plsはちょうど「安全面にいる」とは言いません。あなたが書いていることとその意味を正確に理解する。あなたが理解した後にあなたのコードに入ってくる他のプログラマーは、なぜ構造体が使われたのかを理解しようとすると、一時的に横断的に追跡されます。 "彼は理由のために揮発性の使用する必要があります、私は何を見ていないのですか?" – brettw

関連する問題