web-dev-qa-db-ja.com

Javaの同期メソッドと同期ブロックの違いは何ですか?

Javaの同期されたメソッドと同期されたブロックの違いは何ですか?

私はネットで答えを探していましたが、人々はこれについてあまり確信が持てないようです:-(

私の見解では、同期ブロックがスコープ内でよりローカライズされているため、ロックの時間が短くなることを除いて、2つの間に違いはないでしょう。

そして、静的メソッドのロックの場合、何がロックされますか?ロックオンクラスの意味は何ですか?

36
Geek

同期されたメソッドは、メソッドレシーバーをロックとして使用します(非静的メソッドの場合はthis、静的メソッドの場合は囲んでいるクラス)。 Synchronizedブロックは、式をロックとして使用します。

したがって、次の2つの方法はプロスペクトのロックと同等です。

synchronized void mymethod() { ... }

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

静的メソッドの場合、クラスはロックされます:

class MyClass {
  synchronized static mystatic() { ... }

  static mystaticeq() {
    syncrhonized (MyClass.class) { ... }
  }
}

同期されたブロックの場合、null以外のオブジェクトをロックとして使用できます。

synchronized (mymap) {
  mymap.put(..., ...);
}

ロック範囲

同期されたメソッドの場合、ロックはメソッドスコープ全体で保持されますが、synchronizedブロックでは、ロックはそのブロックスコープ(クリティカルセクションとも呼ばれます)の間のみ保持されます。実際には、JVMは、synchronizedブロックの実行から一部の操作を削除することにより、安全に実行できることが証明できる場合、最適化を許可されています。

45
notnoop

同期メソッドは省略形です。この:

class Something {
    public synchronized void doSomething() {
        ...
    }

    public static synchronized void doSomethingStatic() {
        ...
    }
}

すべての意図と目的のために、これと同等です:

class Something {
    public void doSomething() {
        synchronized(this) {
            ...
        }
    }

    public static void doSomethingStatic() {
        synchronized(Something.class) {
            ...
        }
    }
}

(どこ Something.classは、クラスSomethingのクラスオブジェクトです。)

つまり、同期ブロックでは、ロックについてより具体的に、いつ使用したいかについて細かく設定できますが、それ以外に違いはありません。

8
jqno

はい、1つの違いです。もう1つは、this以外のオブジェクトのロックを取得できることです。

4
Henning

主な違いは次のとおりです。同期するメソッドを宣言すると、メソッドの本体全体が同期します。ただし、同期ブロックを使用する場合は、メソッドの「クリティカルセクション」のみを同期ブロックで囲み、メソッドの残りの部分はブロックから除外できます。

メソッド全体がクリティカルセクションの一部である場合、実際には違いはありません。そうでない場合は、クリティカルセクションのみの周りに同期ブロックを使用する必要があります。同期ブロックに含まれるステートメントが多いほど、全体的な並列処理が少なくなるため、それらを最小限に抑える必要があります。

私の見解では、同期ブロックがスコープ内でよりローカライズされているため、ロックの時間が短くなることを除いて、2つの間に違いはないでしょう。

はい。あなたが正しいです。 synchronizedメソッドとは異なり、同期されたステートメントは、組み込みロックを提供するオブジェクトを指定する必要があります。

Javaチュートリアルの例:

public void addName(String name) {
    synchronized(this) {
        lastName = name;
        nameCount++;
    }
    nameList.add(name);
}

同期ステートメントは、きめの細かい同期で並行性を改善する場合にも役立ちます。以下の使用例については、同じチュートリアルページで良い例を見つけることができます。

たとえば、クラスMsLunchに2つのインスタンスフィールドc1とc2があり、一緒に使用されることはないとします。これらのフィールドのすべての更新はsynchronizedでなければなりませんが、c1の更新がc2の更新とインターリーブされるのを防ぐ理由はありません。そうすることで、不要なブロックを作成して同時実行性を減らします。 同期メソッドを使用するか、またはこれに関連付けられたロックを使用する代わりに、ロックを提供するためだけに2つのオブジェクトを作成します

そして、静的メソッドのロックの場合、何がロックされますか?ロックオンクラスの意味は何ですか?

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

メソッドを synchronized (non static)とすると、次のようになります。

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

メソッドをstatic synchronizedとして作成した場合:

同じクラスの異なるオブジェクトでstatic synchronizedメソッドを2回呼び出すことはできません。 1つのスレッドがクラスAのオブジェクトに対してstatic synchronizedメソッドを実行している場合、クラスAのオブジェクトのいずれかでstatic synchronizedメソッドを呼び出すすべてのスレッドは、メソッドの実行。

このSEの質問で、同期のより良い代替案を見つけます。

Javaでの同期(これ)を避けますか?

0
Ravindra babu

同期されたメソッドは、メソッドが含まれているオブジェクトインスタンスをロックします。

同期されたブロックが任意のオブジェクトをロックできる場合-通常、インスタンス変数として定義されたミューテックスオブジェクト。これにより、操作中のロックをより詳細に制御できます。

0
madlep