web-dev-qa-db-ja.com

静的メソッドと非静的メソッドの同期の違い

Javaで静的メソッドと非静的メソッドを同期することの違いは何ですか?誰でも例で説明できますか?また、メソッドの同期とコードブロックの同期に違いはありますか?

29
Ammu

これをさらに明確にするために、例を追加してみます。

すでに述べたように、Javaは Monitor の実装です。コードのブロックを同期済みとしてマークすると、オブジェクトがパラメーターとして使用されます。実行中のスレッドがそのようなコードブロックに到達すると、その同じオブジェクトの同期ブロックに他の実行中のスレッドがなくなるまで、最初に待機する必要があります。

_Object a = new Object();
Object b = new Object();
...
synchronized(a){
    doStuff();
}
...
synchronized(b){
    doSomeStuff();
}
...
synchronized(a){
    doOtherStuff();
}
_

上記の例では、doOtherStuff()を実行しているスレッドは、doStuff()を保護するコードのブロックに別のスレッドが入るのをブロックします。ただし、_Object b_ではなく_Object a_で同期されるため、スレッドはdoSomeStuff()の周りのブロックに問題なく入ることができます。

インスタンスメソッド(非静的メソッド)でsynchronized修飾子を使用する場合、それは、引数として「this」を使用する同期ブロックを持つことに非常に似ています。したがって、次の例では、methodA()methodB()は同じように動作します。

_public synchronized void methodA() {
  doStuff();
}
...
public void methodB() {
    synchronized(this) {
        doStuff();
    }
}
_

同期されておらず、同期されたブロックがないmethodC()がそのクラスにある場合、スレッドがそのメソッドに入ることを停止するものは何もないことに注意してください。オブジェクト。

Synchronized修飾子を持つ静的メソッドがある場合、それは、_ClassName.class_を引数として持つ同期ブロックを持つことと実質的に同じです(そのクラスのオブジェクトClassName cn = new ClassName();がある場合、 Class c = cn.getClass();)でそのオブジェクトにアクセスできます

_class ClassName {
  public void static synchronized staticMethodA() {
    doStaticStuff();
  }
  public static void staticMethodB() {
    synchronized(ClassName.class) {
      doStaticStuff();
    }
  }
  public void nonStaticMethodC() {
    synchronized(this.getClass()) {
      doStuff();
    }
  }
  public static void unSafeStaticMethodD() {
   doStaticStuff();
  }
}
_

したがって、上記の例では、staticMethodA()staticMethodB()は同じように動作します。実行中のスレッドは、同じオブジェクトで同期しているため、nonStaticMethodC()のコードブロックへのアクセスもブロックされます。

ただし、実行中のスレッドがunSafeStaticMethodD()にアクセスするのを妨げるものは何もないことを知っておくことが重要です。静的メソッドが「クラスオブジェクトで同期する」と言っても、そのクラスのメソッドへのすべてのアクセスを同期することを意味するものではありません。それは単に、同期するためにClassオブジェクトを使用することを意味します。非安全なアクセスはまだ可能です。

75
Daniel Lundmark

つまり、静的メソッドで同期する場合、インスタンス(オブジェクト)ではなくクラス(オブジェクト)で同期します。つまり、静的メソッドの実行中、クラス全体がブロックされます。したがって、他の静的同期メソッドもブロックされます。

19
PeterMmm

Javaの同期は基本的に monitors の実装です。非静的メソッドを同期する場合、モニターはインスタンスに属します。静的メソッドで同期する場合、モニターは属しますコードのブロックの同期も同じアイデアですが、モニターは指定されたオブジェクトに属しています。それを回避できる場合は、各スレッドが criticalセクション

4
jpm

ブロックの同期とメソッドの同期の間に実質的な違いはありません。基本的に:

void synchronized m() {...}

と同じです

void m() { synchronized(this) {...} }

比較すると、静的同期メソッドは以下と同じです。

static void m() { synchronized(MyClass.class) {...} }
3
Nick

Javaスレッドは、インスタンスに入るときにオブジェクトレベルのロックを取得します同期Javaメソッドに入ると、クラスレベルのロックを取得します静的同期Javaメソッドsynchronized blockを使用することで、コードの重要なセクションのみをロックし、パフォーマンス全体を低下させる可能性のあるメソッド全体のロックを回避できます。

0
Zia

おい、ほんのヒント。あなたの質問とは関係ありません:

Do * Stuff()メソッドのいずれかが

this.a= /*yet another*/ new Object();

または

this.b= /*yet another*/ new Object();

その後、あなたはねじ込まれています。ロックは参照の内部ではなく、値の内部にあるためです。参照 Java同期参照

0
PyMeH

Javadocから https://docs.Oracle.com/javase/tutorial/essential/concurrency/locksync.html

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

public static synchronized void getInstance(){}

クラスのロックを取得すると、実際には、クラスのすべてのインスタンスに対して1つしかない「クラス」クラスインスタンスのロックが取得されます。

public synchronized void getInstance(){}

クラスの複数のオブジェクトを作成でき、各オブジェクトには1つのロックが関連付けられます。

0
Saurabh