常に 'this'をモニターロックとして使用することは可能ですか?

たとえば、2つのカウンタを持つクラスがあります(マルチスレッド環境)。

public class MyClass {
  private int counter1;
  private int counter2;

  public synchronized void increment1() {
        counter1++;
  }

  public synchronized void increment2() {
        counter2++;
  }

}

Theres 2 increment operations not related with each other. But I use same object for lock (this).

クライアントが increment1()メソッドと increment2()メソッドを同時に呼び出すと、 increment2 の呼び出しは increment1 )モニターを this モニターから解放しますか?

それが本当であれば、パフォーマンス上の理由から、各操作ごとに別々のモニタロックを提供する必要があることを意味しますか?

3
私は間違った価値を追加してから取り除いた
追加された 著者 dinesh707,
@ dinesh707 - それは完全に間違っています。 OPはそれが正しいです。
追加された 著者 Brian Roach,
@ dinesh707は、JVMが相互作用しないと判断した場合にのみ表示されます。相互作用する場合は、同期させる必要があります。
追加された 著者 John Dvorak,

7 答え

クライアントが同時にincrement1()メソッドとincrement2()メソッドを同時に呼び出すと、increment1()がこのモニタを解放するまでincrement2の呼び出しはブロックされます。

同じインスタンスで呼び出された場合は、はいです。

そうであれば、パフォーマンス上の理由から、各操作ごとに異なるモニタロックを用意する必要があるのでしょうか?

あなただけがそれを知ることができます。あなたの業績要求はわかりません。実際のコードでは実際には問題がありますか?あなたの本当の事業は長く続くのですか?彼らは頻繁に発生しますか?これの影響を予測するために診断を行ったことがありますか?あなたはあなたのアプリケーションをプロファイリングして、モニターを待つのにどれくらいの時間が費やされているかを知りましたか?

まったく異なる理由で this に同期しないようにしてください。すべてを制御するときにスレッディングを考えるのはすでに難しいですが、モニターを得ることができるものがすべて分からなければ何も隠れていません。 this で同期すると、オブジェクトへの参照を持つコードも同じモニターで同期することができます。たとえば、クライアントは次のものを使用できます。

synchronized (myClass) {
   //Do something entirely different
}

これは、デッドロック、パフォーマンスの問題、あらゆる種類のものにつながる可能性があります。

ただで作成されたオブジェクトを使って、クラス内の private final フィールドを代わりに使用すると、そのモニターを取得するコードはあなたのコードになります。

12
追加された

1) yes it's true that increment1() blocks increment2() and vice versa because they both are implicitly synchronizing on this

2)より良いパフォーマンスが必要な場合は、ロックフリーjava.util.concurrent.atomic.AtomicIntegerクラスを考慮してください

  private AtomicInteger counter1 = new AtomicInteger();
  private AtomicInteger counter2 = new AtomicInteger();

  public void increment1() {
        counter1.getAndIncrement();
  }

  public void increment2() {
        counter2.getAndIncrement();
  }
5
追加された

あなたがここで行ったようにメソッドに同期させると、オブジェクト全体がロックされるため、同じオブジェクトから別の変数にアクセスする2つのスレッドは、お互いをブロックします。

2つのスレッドが異なる変数にアクセスしているときに2つのスレッドが互いにブロックしないように同時にカウンタを1つだけ同期化したい場合は、2つのカウンタを2つの同期ブロックに追加し、ブロック。

2
追加された
あなたはオブジェクト全体をロックします。 - 長い同期メソッドobオブジェクトを呼び出すと、同期メソッドが停止するまでこのオブジェクトを使用できません。
追加された 著者 MyTitle,
このオブジェクトを使用することはできますが、このオブジェクトに対してmonitor_enterをロックとして実行することはできません!インクリメント2に対する別の呼び出し(これは "this"オブジェクトをロックする必要もあります)を待たなければなりません。
追加された 著者 StarPinkER,

同じObjectを使用すると、パフォーマンスのボトルネックになります。個々のカウンタに異なるロックを使用することも、同時カウンタとして java.util.concurrent.atomic.AtomicInteger を使用することもできます。

次のように:

public class Counter {
  private AtomicInteger count = new AtomicInteger(0);
  public void incrementCount() {
    count.incrementAndGet();
  }
  public int getCount() {
    return count.get();
  }
}
2
追加された

はい、指定されたコードは以下と同じです:

  public void increment1() {
        synchronized(this) {
             counter1++;
        }
  }

  public oid increment2() {
        synchronized(this) {
             counter2++;
        }
  }

これは同時に1つのメソッドしか実行できないことを意味します。別のロックを提供するか、または this をロックすることは悪い考えです。もう1つは実際にここに必要なものです。 AtomicInteger

1
追加された

複数のスレッドがオブジェクトのメソッドを呼び出そうとしている場合は、ロックを取得しようとするのを待つことになります(ただし、ロックを取得する順序は保証されません)。すべての場合と同様、最適化する理由はありませんあなたのコードの首。

1
追加された

両方の操作を並行して呼び出すことができるために得られるパフォーマンス上の利点が必要な場合は、異なる操作に異なるモニター・オブジェクトを指定しないでください。

しかし、時期尚早の最適化のためには何かがあり、プログラムをより複雑にする前に必要があることを確認する必要があります。

0
追加された