57

同じオブジェクトで 2 回同期すると、Java で奇妙な動作が発生するかどうか疑問に思っていましたか?

シナリオは次のとおりです

pulbic class SillyClassName {

    object moo;
    ...
    public void method1(){
        synchronized(moo)
        {
            ....
            method2();
            ....
        }
    }

    public void method2(){
        synchronized(moo)
        {
            doStuff();
        }
    }
}

どちらのメソッドもオブジェクトを使用し、同期されます。ロックされているため、最初のメソッドによって呼び出されたときに 2 番目のメソッドが停止しますか?

同じスレッドなのでそうは思いませんが、他に奇妙な結果が生じる可能性があるかどうかはわかりません.

4

6 に答える 6

83

再入可能

同期ブロックは再入可能ロックを使用します。つまり、スレッドがすでにロックを保持している場合、問題なく再取得できます。したがって、コードは期待どおりに機能します。

Java チュートリアルページIntrinsic Locks and Synchronizationの下部を参照してください。

2015 年 1 月時点で引用すると…</p>

再入可能同期

スレッドは、別のスレッドが所有するロックを取得できないことを思い出してください。ただし、スレッドは既に所有しているロックを取得できます。スレッドが同じロックを複数回取得できるようにすると、再入可能な同期が可能になります。これは、同期されたコードが直接的または間接的に、同期されたコードも含むメソッドを呼び出し、両方のコード セットが同じロックを使用する状況を表します。再入可能な同期がなければ、同期されたコードは、スレッド自体がブロックされるのを避けるために、さらに多くの予防策を講じる必要があります。

于 2008-10-30T11:45:20.540 に答える
4

私たちはあなたがやろうとしていることにリエントラントロックを使わなければならないと思います。これはhttp://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/locks/ReentrantLock.htmlからの抜粋です。

リエントラントロックとはどういう意味ですか?ロックに関連付けられた取得カウントがあり、ロックを保持しているスレッドが再度取得した場合、取得カウントが増加し、ロックを2回解放して、実際にロックを解放する必要があります。これは、同期のセマンティクスと類似しています。スレッドがすでに所有しているモニターによって保護されている同期ブロックにスレッドが入ると、スレッドは続行でき、スレッドが2番目(またはそれ以降)の同期ブロックを出るときにロックは解放されず、解放されるだけです。それが最初の同期されたブロックを出るとき、それはそのモニターによって保護されて入りました。

私は試していませんが、上記のことを実行したい場合は、リエントラントロックを使用する必要があると思います。

于 2012-04-04T20:31:51.360 に答える
2

Java は、同じスレッドによる 1 つのオブジェクトのネストされたロックを完全にサポートしているようです。これは、スレッドがオブジェクトに対して外部ロックと内部ロックを持っていて、別のスレッドが同じオブジェクトをロックしようとした場合、最初のスレッドによって両方のロックが解放されるまで、2 番目のスレッドが中断されることを意味します。

私のテストは Java 6 SE で行われました。

于 2011-11-10T20:26:14.183 に答える
1

Javaでは、synchronizedメソッドのキーワードは基本的に現在のオブジェクトに同期するため、実際には上記の提案を暗黙的に実行しています。

あなたが言うように、現在のスレッドはすでにそのオブジェクトのロックを保持しているため、あるメソッドで 1 つのオブジェクトを同期し、別のメソッドで同じオブジェクトを同期しても問題は発生しません。

于 2008-10-30T11:40:09.863 に答える
1

問題はありません。あなたの例では(コードを修正してコンパイル警告を取り除くと;))、同期により、method1とmethod2のブロックが同時に実行されなくなります。

それは一種の同期点です。:)


編集:申し訳ありませんが、質問の一部を見逃しましたが、フィルが答えました。要約すると、単一のスレッド自体がデッドロックすることはありません。

于 2008-10-30T11:41:14.417 に答える
0

いいえ、最初のメソッドによって呼び出された場合、2 番目のメソッドは停止しません。奇妙な結果は発生しません (ロックをチェックするためのわずかなオーバーヘッドを除いて。これは大した問題ではありません。Java 6 以降では、JVM - Java SE 6 Performance White Paperにロックの粗大化があります。)

たとえば、java.util.Vector のソース コードを見てください。同期されたメソッド内から他の同期されたメソッドへの呼び出しが多数あります。

于 2008-10-30T15:46:24.437 に答える