web-dev-qa-db-ja.com

Java同期静的メソッド:オブジェクトまたはクラスのロック

Javaチュートリアルには、「同じオブジェクトで同期化されたメソッドを2回呼び出すことでインターリーブすることはできません」とあります。

これは静的メソッドにとって何を意味しますか?静的メソッドにはオブジェクトが関連付けられていないため、同期キーワードはオブジェクトではなくクラスをロックしますか?

144
jbu

静的メソッドには関連付けられたオブジェクトがないため、同期キーワードはオブジェクトではなくクラスをロックしますか?

はい。 :)

125
OscarRyz

オスカーの(簡単に!)答えに少し詳細を追加するために、Java言語仕様の関連セクションは 8.4.3.6、 'synchronized Methods' です。

同期メソッドは、実行前にモニター(§17.1)を取得します。クラス(静的)メソッドの場合、メソッドのクラスのClassオブジェクトに関連付けられたモニターが使用されます。インスタンスメソッドの場合、これに関連付けられたモニター(メソッドが呼び出されたオブジェクト)が使用されます。

198
Cowan

注意しなければならない点の1つは(いくつかのプログラマーは一般にそのtrapに陥ります)、同期された静的メソッドと同期された非静的メソッドの間にリンクがないことです。

class A {
    static synchronized f() {...}
    synchronized g() {...}
}

メイン:

A a = new A();

スレッド1:

A.f();

スレッド2:

a.g();

f()とg()は互いに同期していないため、完全に同時に実行できます。

79
jfpoilpret

次のようにg()を実装しない限り:

g() {
    synchronized(getClass()) {
        ...
    }
}

このパターンは、オブジェクトの異なるインスタンス間で相互排他を実装する場合にも役立ちます(たとえば、外部リソースにアクセスするときに必要です)。

13
user267405

Intrinsic Locks and Synchronization のOracleドキュメントページをご覧ください。

静的メソッドはオブジェクトではなくクラスに関連付けられているため、静的同期メソッドが呼び出されるとどうなるのかと疑問に思われるかもしれません。 この場合、スレッドは、クラスに関連付けられたClassオブジェクトの組み込みロックを取得しますしたがって、クラスの静的フィールドへのアクセスは、クラスのインスタンスのロックとは異なるロックによって制御されます

4
Ravindra babu

以下の例は、クラスとオブジェクトのロックをより明確にします。以下の例が他の人にも役立つことを願っています:)

たとえば、1つのクラスを取得し、他のオブジェクトをロックするメソッドを以下に示します。

public class MultiThread {

    public static synchronized void staticLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }

    public synchronized void objLock() throws InterruptedException {
        for (int i = 0; i < 10; i++) {
            Thread.sleep(100);
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
    }
}

そのため、次のシナリオを作成できます。

  1. 同じオブジェクトを使用するスレッドがobjLockまたはstaticLockメソッドに同時にアクセスしようとした場合(つまり、両方のスレッドが同じメソッドにアクセスしようとしている場合)

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
    
  2. 同じオブジェクトを使用するスレッドがstaticLockおよびobjLockメソッドに同時にアクセスしようとした場合(異なるメソッドへのアクセスを試行)

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
    
  3. 異なるオブジェクトを使用するスレッドがstaticLockメソッドにアクセスしようとしたとき

    Thread-0 0
    Thread-0 1
    Thread-0 2
    Thread-0 3
    Thread-0 4
    Thread-1 0
    Thread-1 1
    Thread-1 2
    Thread-1 3
    Thread-1 4
    
  4. 異なるオブジェクトを使用するスレッドがobjLockメソッドにアクセスしようとしたとき

    Thread-0 0
    Thread-1 0
    Thread-0 1
    Thread-1 1
    Thread-0 2
    Thread-1 2
    Thread-1 3
    Thread-0 3
    Thread-0 4
    Thread-1 4
    
2
Ravi

静的メソッドにもオブジェクトが関連付けられています。 JDKツールキットのClass.classファイルに属します。 .classファイルがRAMにロードされると、Class.classはテンプレートオブジェクトと呼ばれるそのインスタンスを作成します。

例:-のような既存の顧客クラスからオブジェクトを作成しようとするとき

Customer c = new Customer();

Customer.classがRAMにロードされます。その瞬間、JDKツールキットのClass.classはTemplateオブジェクトと呼ばれるオブジェクトを作成し、そのCustomer.classをそのテンプレートオブジェクトにロードします。そのCustomer.classの静的メンバーは、そのテンプレートオブジェクトの属性とメソッドになります。

そのため、静的メソッドまたは静的属性にもオブジェクトがあります

クラスオブジェクトでロックされている静的同期メソッドに慣れていない人向け文字列クラスの場合はString.classで、インスタンス同期メソッドはJavaの「this」キーワードで示されるオブジェクトの現在のインスタンスをロックします。これらのオブジェクトは両方とも異なるロックを持っているため、1つのスレッドが静的同期メソッドを実行している間、Javaの他のスレッドは、そのスレッドが戻るのを待つ必要がなく、バイトで示される個別のロックを取得します.classリテラルおよび静的同期メソッドに入ります。

0
Pragya