web-dev-qa-db-ja.com

同期ブロック内の静的ロックオブジェクトと非静的ロックオブジェクト

同期を視覚化して理解しようとしています。

  1. 静的ロックオブジェクト(code A)とa非静的ロックオブジェクト(コードB) for 同期ブロック
  2. 実際のアプリケーションではどう違いますか?
  3. 他の人にはない落とし穴は何ですか?
  4. どちらを使用するかを決定する基準は何ですか?

コードA

public class MyClass1 {
  private static final Object lock = new Object();
  public MyClass1() {
    //unsync
    synchronized(lock) {
      //sync
    }
    //unsync
  }
}

コードB

public class MyClass2 {
  private final Object lock = new Object();
  public MyClass2() {
    //unsync
    synchronized(lock) {
      //sync
    }
    //unsync
  }
}

上記のコードはコンストラクターを示していますが、静的メソッドと非静的メソッドでの動作の違いについても説明できます。また、同期ブロックが静的メンバー変数を変更しているときに静的ロックを使用すると有利ですか?

私はすでに この質問 で答えを見ましたが、異なる使用シナリオが何であるかは十分に明確ではありません。

36
ADTC

違いは簡単です。ロックされたオブジェクトがstaticフィールドにある場合、_MyClass*_のすべてのインスタンスは共有そのロック(つまり、2つのオブジェクトは使用できません)そのオブジェクトを同時にロックします)。

フィールドが非静的の場合、各インスタンスは独自のロックを持つため、メソッド(同じオブジェクト上)の呼び出しのみが相互にロックします。

静的ロックオブジェクトを使用する場合:

  • スレッド1はo1.foo()を呼び出します
  • スレッド2はo1.foo()を呼び出し、スレッド1が終了するまで待機する必要があります
  • スレッド3はo2.foo()を呼び出し、alsoスレッド1(そしておそらく2)が終了するのを待たなければなりません

非静的ロックオブジェクトを使用する場合:

  • スレッド1はo1.foo()を呼び出します
  • スレッド2はo1.foo()を呼び出し、スレッド1が終了するまで待機する必要があります
  • スレッド3はo2.foo()を呼び出します。スレッド1と2を気にせずに続行できます

どれが必要なのかは、同期ブロックでprotectを試みるデータの種類によって異なります。

経験則として、ロックオブジェクトには、操作対象の値と同じstatic- nessが必要です。したがって、非静的な値onlyを操作する場合、非静的なロックオブジェクトが必要になります。静的な値onlyを操作する場合、静的ロックオブジェクトが必要になります。

静的および非静的値を操作すると、複雑になります。 easyの方法は、静的ロックオブジェクトを使用することですが、これにより、同期ブロックのサイズが絶対的に必要以上に大きくなり、必要以上にロック競合が必要になる場合があります。そのような場合、静的ロックオブジェクトと非静的ロックオブジェクトの組み合わせが必要になる場合があります。

特定のケースでは、コンストラクターでロックを使用します。これはインスタンスごとに1回だけ実行されるため、ここでは非静的ロックオブジェクトは意味をなしません。

49
Joachim Sauer