2012-05-24 14 views
5

私は以下のスニペットのように見えるいくつかの(生産!)コードに走った:私は、これはすべての種類の対象となることを期待する(ジャワ)、そのオブジェクトに基づいて、同期ブロック内のオブジェクトの割り当て

synchronized(some_object) { 
    some_object = new some_object() 
} 

恐ろしい競争条件があり、2番目のスレッドが新しいオブジェクトが作成されたブロックに入る可能性があります。私のJavaのチョップは、上記の予想される動作を明確に述べるには十分ではないので、私がこれをリファクタリングする前に皆さんが言いたいことがあります。

答えて

2

フランシスさんの言うとおり、これは問題ではないかもしれません。あなたのスニペットは次のようになります。

SomeObject saved = some_object; 
synchronized(saved) { 
    some_object = new SomeObject() 
} 
+0

これはあまり書かれていません。私の場合、クラスには、同期ブロックに使用される変数some_objectがあり、この変数は同じブロック内で再割り当てされています。 –

+0

+1ここでキーとは、同期が参照ではなくオブジェクトを参照するということです。 'new'が実行されて割り当てられた後、あなたはまだ古いオブジェクトにロックされます。この時点で新しいオブジェクトはロックされません。同期化されたブロックが終了すると、古いオブジェクトのロックが解除され、他の参照が存在しない場合は、gcに適格です。実際の同期化されたブロックにもっと多くのコードがあり、それが何らかの形で新しいオブジェクトに転送されるロックに依存する場合、問題が発生する可能性があります。 –

+1

ありがとうございました。ロックがオブジェクトにあり、リファレンスではないという事実は私には意味をなさない。私がぼやけていたのは、その変数によって参照されるオブジェクトが変更されたとき、別のスレッドが別のロックされていないオブジェクトを参照して再びブロックに入るか、同期ブロックの仕組みが起こるのを防ぐかでした。 –

4

これは実際に何が起こっているかによっては問題ありません。より大きな文脈を理解する必要があります。同期は、ブロックの先頭のsome_objectが指し示すオブジェクト上にあります。あなたの説明からバグであることを知るには十分な情報がありません。

同期自体は正常に動作します。

1

同期は、同期ブロックを入力するときに参照されたオブジェクトにあります。同期ブロック内の別のオブジェクトへの参照をポイントしても、同期にはまったく影響しません。それは "古い"オブジェクトに対してまだ同期しています。

1

これはかなり悪いです。同期は、最終クラスのメンバーに最もよく使用されます。

スレッドセーフな方法でオブジェクトを作成する現代的なアプローチは、GoetzのJava Concurrency in Action(第15章)で説明したように、ループ内でAtomicReference compareAndSetを使用することです。これはあなたのスレッドをブロックするものではなく、同期ブロックよりもはるかに優れたパフォーマンスを提供します。

private final AtomicReference<SomeObject> someObject = new AtomicReference<>(); 


void buildIt() { 
    SomeObject obj = new SomeObject(); 
    SomeObject current = someObject.get(); //probably null, but doesn't matter 
    while (true) { 
     if (someObject.compareAndSet(current, obj)) 
      break; 
    } 
} 
関連する問題