In Java同じオブジェクトで2回同期すると、奇妙な動作が発生するのではないかと思っていました。
シナリオは次のとおりです
pulbic class SillyClassName {
object moo;
...
public void method1(){
synchronized(moo)
{
....
method2();
....
}
}
public void method2(){
synchronized(moo)
{
doStuff();
}
}
}
どちらのメソッドもオブジェクトを使用し、オブジェクト上で同期されます。最初のメソッドによって呼び出されたときに2番目のメソッドは、ロックされているために停止しますか?
同じスレッドなのでそうは思いませんが、他に奇妙な結果が生じるかどうかはわかりません。
同期されたブロックはreentrantロックを使用します。つまり、スレッドがすでにロックを保持している場合、問題なく再取得できます。したがって、コードは期待どおりに機能します。
Javaチュートリアル ページの下部を参照してください 固有のロックと同期 。
2015-01現在の見積もり…
リエントラント同期
スレッドは別のスレッドが所有するロックを取得できないことを思い出してください。ただし、スレッドは、すでに所有しているロックを取得できます。スレッドが同じロックを複数回取得できるようにすると、再入可能同期が有効になります。これは、同期されたコードが直接的または間接的に、同期されたコードも含むメソッドを呼び出し、両方のコードセットが同じロックを使用する状況を示しています。再入可能な同期がないと、同期されたコードは、スレッドがそれ自体をブロックしないようにするために、多くの追加の予防措置を講じる必要があります。
私たちはあなたがやろうとしていることにリエントラントロックを使わなければならないと思います。これは http://docs.Oracle.com/javase/1.5.0/docs/api/Java/util/concurrent/locks/ReentrantLock.html からの抜粋です。
リエントラントロックとはどういう意味ですか?ロックに関連付けられた取得カウントがあり、ロックを保持しているスレッドが再度取得した場合、取得カウントが増加し、ロックを実際に解放するには、ロックを2回解放する必要があります。これは、同期のセマンティクスと類似しています。スレッドがすでに所有しているモニターによって保護されている同期ブロックにスレッドが入ると、スレッドは続行が許可され、スレッドが2番目(または後続)の同期ブロックを出るときにロックは解放されず、解放されるだけです。最初に同期されたブロックを出ると、そのモニターによって保護されて入りました。
私は試していませんが、上記のことを実行したい場合は、リエントラントロックを使用する必要があると思います。
Javaは、同じスレッドによる1つのオブジェクトのネストされたロックを完全にサポートしているように見えます。これは、スレッドがオブジェクトに対して外部ロックと内部ロックを持ち、別のスレッドが同じオブジェクトをロックしようとすると、2番目のスレッドは次のようになるまで中断されることを意味します。 両方とも ロックは最初のスレッドによって解放されました。
私のテストはJava 6SEで行われました。
Javaでは、メソッドのsynchronized
キーワードは基本的に現在のオブジェクトで同期するため、事実上、上記で提案したことを暗黙的に実行します。
あなたが言うように、現在のスレッドはすでにそのオブジェクトのロックを保持しているので、あるメソッドで1つのオブジェクトを同期してから、別のメソッドで同じオブジェクトを同期しても問題は発生しません。
問題はありません。あなたの例では(コードを修正して、表示されるコンパイル警告を取り除くと;))、同期により、method1とmethod2のブロックが同時に実行されないことが保証されます。
それが同期のポイントのようなものです。 :)
編集:申し訳ありませんが、あなたの質問の一部を見逃しましたが、フィルはそれに答えました。要約すると、単一のスレッドがそれ自体をデッドロックすることはできません。
いいえ、最初に呼び出されても2番目のメソッドは停止しません。奇妙な結果は発生しません(ロックをチェックするためのわずかなオーバーヘッドを除いて。これはそれほど重要ではありません。Java 6以降、JVMでロックが粗くなります--- http:// Java。 Sun.com/performance/reference/whitepapers/6_performance.html )
たとえば、Java.util.Vectorのソースコードを見てください。同期メソッド内から他の同期メソッドへの呼び出しがたくさんあります。