web-dev-qa-db-ja.com

同期オブジェクトがnullに設定されました

2つのスレッドThread1およびThread2

//Within Thread1     
synchronized(obj1)  
{  
    obj1 = null;  
}  

//Within Thread2  
synchronized(obj1)  
{  
    do something  
}   

Jvmが最初にthread1を実行し、obj1をnullに設定した場合、thread2はその変更をすぐに確認しますか、それとも時間がかかり、obj1はまだnullではないため、jvmはthread2同期ブロックを実行できますか?

26
vjk

これはほぼ確実に同期の抽象化を壊します-thread2はすぐに変更を確認します。同期しているオブジェクトの参照は絶対に変更しないでください。これをnullに設定すると、それ以上同期しようとするとNullPointerExceptionが発生します。

38
Louis Wasserman

まず、同期に使用される変数の変更はひどく悪いこと™であることを強調しておきます。 obj1finalである必要があり、モニターとして使用する場合は触れないでください。

とはいえ、あなたの質問に戻りましょう:

JVMが最初にThread1を実行する場合、obj1で同期し、それをnullに設定してスレッドが終了します。 2番目のスレッドがobj1で同期しようとすると、NullPointerExceptionがスローされます。 obj1の変更は同期ブロックで行われたため、Thread2が更新された値を確認できることが保証されています(つまり、NullPointerExceptionが保証されています)。

obj1のロックを取得した後、参照をクリアする前にThread1が中断された場合、Thread2はobj1をロックし、Thread1が完了するまで待機します。次に、以前にobj1によって参照されたオブジェクトがまだ存在するため、モニターに正常に入る。

12

synchronizedは、参照ではなくオブジェクトで同期します。 obj1(参照)をnullに設定すると、以前はobj1がポイントしていたオブジェクトでthread2が同期できなくなり、代わりにNullPointerExceptionを取得します。

4
Steve Kuo

変更は即時です。スレッド1がロックを「所有」すると、obj1の値を自由に変更できます。スレッド2は、スレッド1がロックを解放するまで待機する必要があります。 obj1 == nullが確実に表示されます

1
mprivat

簡単な修正は、オブジェクトを1要素の単純な配列にして、同期のためにその配列を参照することです。たとえば、

Object [] obj1 = {null};

配列の存在に影響を与えることなく、要素をnullにすることができます。確かに、これは依然としてオブジェクト自体を同期で使用しないという「ルール」に違反しますが、コードが他の場所で問題を複雑にしない限り、このクイックフィックスは期待どおりに機能するはずです。

1
Jerry Miller