2016-07-30 4 views
4

これは、Joshua Blochによって書かれた本から取られています。スレッドがすでに保持しているロックを取得しようとするとどうなりますか?

私はネイティブの英語のスピーカーではないため、疑念の明確化を求める理由があります。スレッドが既に保持しているロックを取得するために をしようとすると、本来のロックは、再入可能であるため、

、要求 は成功します。リエントラントとは、**呼び出し単位ではなくスレッドごとに でロックが取得されることを意味します。

呼び出しごとに、メソッドごとにコールすることを意味しますか? スニペットを検討:

class Factoriser{ 

     public synchronized void doSomething(){ 
      // code goes here 
     } 
} 

がスレッドAであり、インスタンスメソッドのdoSomething()を持つオブジェクトのロックを取得することができると仮定する。何らかの理由で同じスレッドのスレッドAが再び同じオブジェクトインスタンスメソッドdoSomething()のロックを取得します(以前のロックがまだ解放されていないことも想像してください)。

Joshuaのステートメントを正しく理解すると、2つのメソッド呼び出し/呼び出しがあっても、ロックは1つだけになります。私の理解は100%正しいですか?例を挙げてください。私は混乱しています。なぜなら、著者は以下の段落でこれを明らかにしています。

リエントラントは、各ロックと取得カウントと所有スレッドを関連付けることによって実装されます。カウントがゼロの場合、ロックは保持されていないとみなされます。スレッドが以前に保持されていないロックを取得すると、JVMは所有者 を記録し、取得カウントを1に設定します。同じスレッド が再びロックを取得した場合、カウントは増分され、所有スレッドが同期ブロックを終了するときに になると、 のカウントがデクリメントされます。カウントがゼロになると、ロックが解除されます。

Reentrancy/locksの取得が呼び出し単位でない場合、私が上記のシナリオでJVMによって行われたカウントが2に設定されているのはなぜですか?

+2

** **太字**の**ロット**です。 ** ** ** ** ** ** ** ** ** ** ** ** **実は、**大胆に** **無意味**と**気を散らす**となっています。 – Andreas

+0

オブジェクトごとに1つのロックしかありません。任意の数の呼び出しは、同じロックを必要とするだけです(正常に)。最後のロックが解除されると、オブジェクトはロックされなくなります。なぜこれは難しいのですか? – markspace

+0

@アンドレアス:ありがとう。削除されました。 –

答えて

2

このカウンタは、ロックの取得と排泄を一致させるために使用されます。ロックは、カウンタが0​​ような方法foo()をマーキングし、オブジェクトobjでそれを呼び出しているときにのみ解放することができ、次のブロックと同じです。

// calling obj.foo() 
synchronized(obj) { 
    // Do the foo-work 
} 

は、我々は2つのsynchronizedメソッドを持っていると仮定しましょう:foo()bar()と後者は前者から呼ばれます。ステップ3で、我々は我々が外同期ブロックに残っているため、エラーになり、ロックを解放する、カウンターがなければ

final FooBar obj = new FooBar(); 

// calling obj.foo() 
synchronized(obj) { // 1. here the lock is acquired, the counter is set to 1 

    // do some foo-work 

    // calling obj.bar() 
    synchronized(obj) { // 2. the same lock object, the counter is set to 2 
     // do the bar-work 
    } // 3. the counter is set to 1, the lock is still not released 

    // continue doing the foo-work 
} // 4. the counter is 0, the lock is released 

:呼び出しは、次のような構造を持つことになります。したがって、再入国を正しく実施するにはカウンターが必要です。

+0

オブジェクト全体がロックされていますか?または、そのオブジェクトに対してsynchronizedとしてマークされたメソッドのみ。 –

+0

私はあなたの質問を完全に理解しているかどうかはわかりません。すべての同期メソッドは同じロックオブジェクトを使用します - これらのメソッドが呼び出されるオブジェクト(静的同期メソッドは 'Class'オブジェクトを使用します)。したがって、オブジェクト全体がロックされていると言うことができます。しかし、synchronizedとしてマークされていないメソッドは、アクティブなロックに関係なく引き続き呼び出すことができます。同期された各メソッドを非同期のメソッドと考えるだけで、このメソッドが呼び出されたオブジェクトで同期化されたブロックに配置されます。これは私の答えで示したとおりです。多くのことを理解しやすくなります。 –

+0

そして、メソッド自体がロックされていないことが重要です。あるスレッドですでに呼び出されていて、まだ動作している特定のオブジェクト(または静的であればクラス)に対してのみ 'ロック'することができます。同時に、別のスレッドは別のオブジェクトで同じメソッドを呼び出すことができ、ロックするために別のオブジェクトを使用するため、ブロックされません。したがって、ロックされたオブジェクトであり、メソッドではありません。しかし、これらのロックは、同じオブジェクトを使用する同期メソッドと同期ブロックにのみ影響します。 –

関連する問題