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


148

Javaのドキュメントは言う:

同じオブジェクト上の同期メソッドの2つの呼び出しをインターリーブすることはできません。

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

回答:


129

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

はい。:)


81
みんなが理解できるように、精巧に答えてください。
マドゥ

6
@マドゥ。つまり、同じクラスに2つ以上の同期されたメソッドがある場合、そのクラスのインスタンスが複数ある場合でも、両方を同時に実行することはできません。ロックは基本的に、各同期メソッドのObject.classのロックと同じです。
スティーブン

この答えは間違っています- thisインスタンスメソッドでロックが取得されています- オスカーを修正してください。
vemv 2012年

1
@vemv問題はインスタンスメソッドではなく、クラスメソッドに関するものです。
OscarRyz 2012年

23
@vemvそうですね、答えを理解するには、まず質問を読む必要があります。
OscarRyz 2012年

199

オスカーの回答に少し詳細を追加するだけで(喜ばしいほど簡潔です!)、Java言語仕様の関連セクションは8.4.3.6の「同期メソッド」です。

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



80

注意する必要がある1つの点(通常、いくつかのプログラマーはその罠に陥ります)は、同期された静的メソッドと同期された非静的メソッドの間にリンクがないということです。

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

メイン:

A a = new A();

スレッド1:

A.f();

スレッド2:

a.g();

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


18
しかし、g()がf()が読み取っている静的変数を変更している場合はどうでしょうか。そのスレッドを安全にするにはどうすればよいですか?次に、クラスのロックを明示的に取得しますか?
バスキン

22
はい、あなたの非静的メソッドは、明示的にクラス自体(すなわち、上で同期する必要がありますsynchronized (MyClass.class) {...}
jfpoilpret

@jfpoilpret "synchronized(MyClass.class){...}"は、このメソッドを静的に同期させることと同じですよね?
crazymind

15

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

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

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


63
実際には、非常に微妙で厄介なバグが発生する可能性があることに注意してください。ランタイムタイプをgetClass()返すことを忘れないでください。クラスをサブクラス化すると、親クラスと子クラスは異なるロックで同期します。すべてのインスタンスが同じロックを使用することを確認する必要がある場合の方法です。synchronized(MyClass.class)
Cowan、

4

本質的なロックと同期に関するオラクルのドキュメントページをご覧ください。

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


2

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

例:-既存の顧客クラスからオブジェクトを作成しようとした場合

Customer c = new Customer();

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

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


2

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

たとえば、以下のメソッドには、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 OR 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. 同じオブジェクトを使用するスレッドが同時にメソッドstaticLockobjLockメソッドにアクセスしようとしたとき(異なるメソッドへのアクセスを試行)

    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

0

クラスオブジェクトでロックされた静的な同期メソッドに慣れていない人は、たとえば、文字列クラスの場合はString.classを、インスタンス同期メソッドはJavaの「this」キーワードで示されるオブジェクトの現在のインスタンスをロックします。これらのオブジェクトは両方とも異なるため、ロックも異なります。したがって、1つのスレッドが静的同期メソッドを実行している間、Javaの他のスレッドは、そのスレッドが戻るのを待つ必要はありません。静的同期メソッド。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.