web-dev-qa-db-ja.com

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

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

void synchronized method1() {
     method2()
}

void synchronized method2() {
}
76
user705414

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

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

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

スレッド呼び出しがmethod1からmethod2に入ると、thisへのロックを保持していることを確認します。ロックは既に保持されているため、パススルーできます。

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

コメントでジェームス・ブラックが述べたように、メソッド本体の内部で何をするのかを意識する必要があります。

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

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

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

突然ConcurrentModificationExceptionを見ているため、スレッドセーフではありません。なぜならmethod3は非同期であるため、スレッドBがmethod1

97
pickypg

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

一般的に言うことはできません。それは、メソッドが何をするか、および同じクラスおよび他のクラスの他のメソッドが何をするかに依存します。

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

5
Stephen C

Java Tutorials site http://download.Oracle.com/javase/tutorial/essential/concurrency/syncmeth.html から

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

  2. 同期メソッドが終了すると、同じオブジェクトに対する同期メソッドの以降の呼び出しと発生前の関係が自動的に確立されます。これにより、オブジェクトの状態への変更がすべてのスレッドから見えるようになります。

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

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

また、不必要にロックしているかどうか、使用したコードthisが原因で、オブジェクトが1つの変数への同期アクセスのみを必要とする場合、オブジェクト全体をロックしますその変数をロックするだけです。

1
Stephen Lee