2つのスレッドThread1
およびThread2
//Within Thread1
synchronized(obj1)
{
obj1 = null;
}
//Within Thread2
synchronized(obj1)
{
do something
}
Jvmが最初にthread1を実行し、obj1をnullに設定した場合、thread2はその変更をすぐに確認しますか、それとも時間がかかり、obj1はまだnullではないため、jvmはthread2同期ブロックを実行できますか?
これはほぼ確実に同期の抽象化を壊します-thread2
はすぐに変更を確認します。同期しているオブジェクトの参照は絶対に変更しないでください。これをnull
に設定すると、それ以上同期しようとするとNullPointerException
が発生します。
まず、同期に使用される変数の変更はひどく悪いこと™であることを強調しておきます。 obj1
はfinal
である必要があり、モニターとして使用する場合は触れないでください。
とはいえ、あなたの質問に戻りましょう:
JVMが最初にThread1を実行する場合、obj1
で同期し、それをnull
に設定してスレッドが終了します。 2番目のスレッドがobj1
で同期しようとすると、NullPointerException
がスローされます。 obj1
の変更は同期ブロックで行われたため、Thread2が更新された値を確認できることが保証されています(つまり、NullPointerException
が保証されています)。
obj1
のロックを取得した後、参照をクリアする前にThread1が中断された場合、Thread2はobj1
をロックし、Thread1が完了するまで待機します。次に、以前にobj1
によって参照されたオブジェクトがまだ存在するため、モニターに正常に入る。
synchronized
は、参照ではなくオブジェクトで同期します。 obj1
(参照)をnullに設定すると、以前はobj1
がポイントしていたオブジェクトでthread2が同期できなくなり、代わりにNullPointerException
を取得します。
変更は即時です。スレッド1がロックを「所有」すると、obj1の値を自由に変更できます。スレッド2は、スレッド1がロックを解放するまで待機する必要があります。 obj1 == nullが確実に表示されます
簡単な修正は、オブジェクトを1要素の単純な配列にして、同期のためにその配列を参照することです。たとえば、
Object [] obj1 = {null};
配列の存在に影響を与えることなく、要素をnullにすることができます。確かに、これは依然としてオブジェクト自体を同期で使用しないという「ルール」に違反しますが、コードが他の場所で問題を複雑にしない限り、このクイックフィックスは期待どおりに機能するはずです。