別の同期メソッドから同期メソッドを呼び出すのは安全ですか?


81

同期されたメソッドが別の同期されたメソッドを呼び出す場合、それはスレッドセーフですか?

void synchronized method1() {
     method2()
}

void synchronized method2() {
}

この記事は答えに役立ちますか、それともどこで混乱していますか?kalyanchakravarthy.net/?p=413
James Black

はい-上記のコンテキストでのみ呼び出されると仮定すると、method2を同期済みとしてマークする必要はありません。
debracey 2011

4
また、スレッドセーフであるかどうかは、2つの方法で何が起こるかによって異なります。たとえば、スレッドセーフでないリストを呼び出す場合、他のスレッドがそのコレクションを変更する可能性があると、スレッドセーフではない可能性があります。
ジェームスブラック

私が推測する答えとして、実際の質問があります。はい、synchronizedキーワードは再帰ロックを使用します。別の同期メソッドから同期メソッドを安全に呼び出すことができます。
Brett Kail 2011

しばらく経ちましたが、それでもグーグルで最初のヒットです。そうです:はい、同じオブジェクトの同期されたブロック/メソッドは再入可能です。stackoverflow.com/questions/12219376/reentrant-synchronization
Szocske

回答:


103

はい、メソッドをとしてマークするとsynchronized、実際にこれを実行します。

void method1() {
    synchronized (this) {
        method2()
    }
}

void method2() {
    synchronized (this) {
    }
}

スレッド呼び出しがmethod1からmethod2に入ると、ロックが保持されていることを確認しますthis。これはすでに保持されており、通過できます。

スレッドがmethod1またはmethod2に直接入ると、ロック(this)を取得できるまでブロックされ、その後入ります。

コメントでJamesBlackが指摘しているように、メソッド本体の内部で何をするかを知っておく必要があります。

private final List<T> data = new ArrayList<T>();

public synchronized void method1() {
    for (T item : data) {
        // ..
    }
}

public void method3() {
    data.clear();
}

が同期さConcurrentModificationExceptionれていないため、将来的にaを見ているため、突然スレッドセーフではなくmethod3なり、スレッドBがで動作してmethod1いるときにスレッドAによって呼び出される可能性があります。


私はここで尋ねられたものとほとんど同じ質問に答えようとしています。これらは2つの可能な答えです(他の2つは実行されないと言います)、どちらが正しいですか?C.コードは実行されますが、デッドロック状態が発生する可能性がありますD. Javaがリエントラント同期を提供し、スレッドが同じロックを複数回取得できるようにするため、コードは正常に実行されます----- Dだと思いますが、多分潜在的なデッドロック状況はメソッド本体に依存しますか?

@ user3140993ここのコードにはデッドロックの可能性がありません。method3は安全でないスレッド操作を示していますが、リエントラント同期については注意が必要です。
pickypg 2015

7

同期呼び出しでマークされたメソッドは、別の同期メソッドスレッドセーフです。

一般的に、言うことはできません。それは、メソッドが何をするか、そして同じクラスや他のクラスの他のメソッドが何をするかによって異なります。

ただし、異なるスレッドによって行われた同じオブジェクトでのmethod1とmethod2の呼び出しは、同時に実行されないことを確認できます。メソッドの動作によっては、これらのメソッドに関してクラスがスレッドセーフであると言えば十分な場合があります。


2

Javaチュートリアルサイトhttp://download.oracle.com/javase/tutorial/essential/concurrency/syncmeth.htmlから

  1. 同じオブジェクトで同期されたメソッドの2つの呼び出しがインターリーブすることはできません。1つのスレッドがオブジェクトの同期メソッドを実行している場合、同じオブジェクトブロックの同期メソッドを呼び出す他のすべてのスレッドは、最初のスレッドがオブジェクトで完了するまで実行を一時停止します。

  2. 同期メソッドが終了すると、同じオブジェクトの同期メソッドの後続の呼び出しとの発生前の関係が自動的に確立されます。これにより、オブジェクトの状態への変更がすべてのスレッドに表示されることが保証されます

したがって、Javaは、2つのスレッドが同じメソッドを実行している場合、メソッドが同時に実行されるのではなく、次々に実行されることを保証します。

ただし、活性の問題に注意する必要があります。http://download.oracle.com/javase/tutorial/essential/concurrency/starvelive.html

そしてまた、あなたがuncessarilyロックされているかどうか、コード内の原因は、あなたが使用され、これをあなたのオブジェクトが唯一のあなただけのその変数をロックする必要がある一つの変数への同期アクセスを必要とする場合、オブジェクト全体をロックします、。


@ StephenLee-変数をロックすることはできません。次にsynchronized (this.someVar)、参照がで保持されているオブジェクトを探していると言いますsomeVar。区別は非常に重要です。
スティーブンC
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.