8

オブジェクトロックのコンテキストで、これら2つの例の違いを誰かが説明できますか?

public void method1(){
    synchronized(this){
        ....
    }
}

StringBuffer aStringBufferObject = new StringBuffer("A");

public void method2(){
    synchronized(aStringBufferObject){
        ....
    }
}

最初の例ではthisインスタンスのロックを取得し、2番目の例ではaStringBufferObjectインスタンスのロックを取得することを知っています。しかし、私はその効果や2つの違いが何であるかを本当に理解していません。

たとえば、2番目の例では、ロックが「this」インスタンスに関連していないため、スレッドは同期ブロック内でコードを実行できますか?

メソッドまたはコードのブロックを同期すると、複数のスレッドが同時にそのブロック/メソッドにアクセスできなくなることは知っていますが、ロックするオブジェクトを指定する目的と、オブジェクトの指定方法の違いは何ですか?上記の例?

4

3 に答える 3

8

ロックオンするオブジェクトを指定する目的は何ですか?

this多くの場合、インスタンス上またはインスタンス上で同期する方が簡単ですClass(静的メソッドの場合)。ただし、暗黙的なロックではなく、特定のオブジェクトで同期する必要がある場合があります ( this)。そのような場合は次のとおりです。

  • を使用せずにプリミティブへのアクセスを同期したいthisObjectそれぞれObjectが Java の暗黙的なモニターに関連付けられているため、 でのみ同期できます。プリミティブにはそのような暗黙のモニターがないため、ロック オブジェクトを使用する必要があります。ラッパー クラスを使用することは、特に保護されたブロック内のロック オブジェクトを変更することになる場合は、不適切で不適切な選択です。
  • this同期してもスレッド セーフが保証されない場合に、クリティカル セクションを実際に保護するオブジェクトで同期したい場合。ArrayListたとえば、 class のインスタンス間で共有されるインスタンスへのアクセスを同期Aしている場合、 のインスタンスでの同期は役に立ちませんA。別のスレッドがリストを変更している間に、スレッドが新しいインスタンスを作成Aしてリストにアクセスする場合があります。すべてのスレッドが競合しなければならない別のロックを使用すると、リストを保護できます。このロックは に関連付けられA.classたものである可能性がありますが、同じ保証を提供する任意のオブジェクトである可能性があります。
  • ロック分割を実行して、異なる保護されたブロックが同じロックではなく異なるロックによって保護されるようにする必要があります。つまり、異なるスレッドが異なるクリティカル セクションにアクセスするために異なるロックを取得できるようにすることがスレッド セーフである場合、クリティカル セクションごとに異なるロックを設定できます。

以下は、分割ロックの使用例です。

private Object method1Lock = new Object();
private Object method2Lock = new Object();

public void method1(){
    synchronized(method1Lock){
        ....
    }
}

public void method2(){
    synchronized(method2Lock){
        ....
    }
}

method1と の同時実行がクラスの不変条件に違反しmethod2ないことを保証できる場合は、分割ロックを使用します。このようにして、同じオブジェクトにアクセスする必要があるが異なるメソッドを呼び出すスレッド全体でパフォーマンスを向上させることができます。


あなたの他の質問では、

たとえば、2 番目の例では、ロックが「this」インスタンスに関連していないため、スレッドは同期ブロック内のコードを引き続き実行できますか?

2 番目の例では、保護された領域に入るスレッドは、 に関連付けられたロックを取得する必要がありますaStringBufferObject。別のスレッドがそのロックを保持している場合、現在のスレッドはそれ以上先に進みません。を指定するthisと、スレッドは現在のオブジェクトに関連付けられたロックを取得する必要があります。どちらの場合も、スレッドはロックを取得する必要があります。例は、ロックとして使用されているオブジェクトのみが異なります。

于 2011-07-24T14:41:57.430 に答える
2

オブジェクトで同期するということは、同じオブジェクトで同期する他のブロックが待機する必要があることを意味します。例えば:

public void methodA() {
   synchronized(obj) {
      //Do one job
   }
}

public void methodB() {
   synchronized(obj) {
      //Do another job
   }
}

methodA()あるスレッドを呼び出してmethodB()から別のスレッドを呼び出すと、methodB()終了する前にmethodA()終了しません。

于 2011-07-24T14:24:23.520 に答える
2

synchronizedブロックはモニターであり、ミューテックスをロックおよびロック解除するための詳細を省略します。Java のすべてのオブジェクトには内部ロックがあるため (Objectクラスのソース コードを参照)、synchronizedステートメントを使用すると、JVM はクリティカル セクションを同期するのに役立ちます。パッケージで ReentrantLock を使用して自分でブロックを同期することもできますjava.util.concurrent.locks

于 2011-07-24T14:40:33.707 に答える