2013-05-12 11 views
33

リエントラントは、ロックが呼び出し単位ではなくスレッド単位で取得されることを意味します。'Reentrancy' in java

スレッドが本来のロックを保持しているので、一度実行されたスレッドが呼び出しベースに等しいことを意味しないのですか?処理機能機能doBを呼び出しdoA、およびdoBも、その後、再入可能性があるウィルロックlockAを必要とするとき、私はロックlockAを取得したスレッドで、場合:

は、それを意味するようです、ありがとうございます。 Javaでは、この現象はスレッドごとに取得されるため、デッドロックは考慮する必要はありません。

+0

メソッドロックを入力する場合は想像Xオブジェクト、およびその方法では、あなたは非常に同じメソッドを呼び出します(直接またはさらに上のコールスタックで)、再度対象物Xをロックしながら。何が起こるのですか?すでに保持しているロックを待つか、それを保持しているスレッドが再びスレッドを呼び出すことを知っていて、それを渡すことができますか?これは、再入国と呼ばれています。あなたは既にあなたが以前にいたのと同じ方法を入力します。 – Patashu

+1

はい、Javaの同期ブロックとロックはリエントラントなので、スレッドfooにロックバーが設定されると、最初にロックを解除することなくロックバーを持つメソッドを安全に呼び出すことができます。 – Patashu

+0

デッドロックを考慮する必要があります。デッドロックは、2つのスレッドがお互いに待っているときに発生します。 – rubixibuc

答えて

52

再入は、ロックはスレッド単位ではなく、あたりの呼び出しごとに取得されることを意味します。

これは誤った定義です。それは本当です(一種)、しかしそれは本当の点を見逃します。

Reentrancyは、あなたが何かをしていることを(一般的にCS/ITの用語で)意味しています。あなたがやっている間は、もう一度やり直してください。ロックの場合、それはあなたがシングルスレッドにこのような何かを意味します

  1. 「foo」というのロックを取得します。
  2. 何かを行う
  3. "foo"をロックします。以前に取得したロックを解放していないことに注意してください。リエントラントロック/ロック機構と "foo" という

、同じを取得しようとする試みに

  • ...
  • "foo" という
  • にリリースロック...
  • リリースロックロックが成功し、ロックに属する内部カウンタがインクリメントされます。ロックは、ロックの現在の所有者がそれを2回リリースした場合にのみ解放されます。ここ

    は、プリミティブオブジェクトのロック/モニタ...リエントラントである使用してJavaの例は次のとおり

    Object lock = new Object(); 
    ... 
    synchronized (lock) { 
        ... 
        doSomething(lock, ...) 
        ... 
    } 
    
    public void doSomething(Object lock, ...) { 
        synchronized (lock) { 
         ... 
        } 
    } 
    

    リエントラントの代替は、それが試みるスレッドのエラーであろう非リエントラントロック、ありますすでに保持しているロックを取得します。

    リエントラントロックを使用する利点は、すでに保持しているロックを誤って取得するために失敗する可能性を心配する必要がないことです。欠点は、あなたが呼ぶものがロックが保護するように設計された変数の状態を変更するものではないと想定できないことです。しかし、それは通常問題ではありません。ロックは一般に、他のスレッドによって行われる同時状態変更に対して保護するために使用されます。


    だから私は、デッドロックを考慮する必要はありませんか?

    はい、あります。

    スレッドはデッドロックしません(ロックがリエントラントの場合)。しかし、ロックしようとしているオブジェクトにロックを持っている可能性がある他のスレッドがあると、デッドロックが発生する可能性があります。

  • +0

    スレッドは一度プロセスを実行しているので、私はまだそれをやっている間、どうしたらいいですか? – znlyj

    +1

    今追加したJavaコードの例を参照してください。 –

    +0

    はい、ありがとうございます。 – znlyj

    1

    これは、スレッドにロックが設定されると、コードのロックされたセクションに必要な回数だけ入力できることを意味します。したがって、メソッドなどのコードの同期セクションがある場合、ロックを獲得したスレッドだけがそのメソッドを呼び出すことができますが、同じロックで保持されている他のコードを含め、必要な回数だけそのメソッドを呼び出すことができます。別のメソッドを呼び出すメソッドが1つあり、両方が同じロックで同期されている場合、これは重要です。これが事実でない場合。 2番目のメソッド呼び出しはブロックされます。また、再帰的メソッド呼び出しにも適用されます。

    public void methodA() 
    { 
        // other code 
        synchronized(this) 
        { 
          methodB(); 
        } 
    } 
    
    public void methodB() 
    { 
        // other code 
        syncrhonized(this) 
        { 
          // it can still enter this code  
        } 
    
    } 
    
    13

    このようなものを想像:今、私たちは次のことが起こるA.を呼び出す

    function A(): 
        lock (X) 
         B() 
        unlock (X) 
    
    function B(): 
        A() 
    

    を:

    • 我々が入力し、X
    • をロックし、我々は再び入るB
    • を入力します。 、再びXをロックする

    w eはAの最初の呼び出しを終了しませんでしたが、Xはまだロックされています。これは再入場と呼ばれ、関数Aはまだ返っていないが、関数Aが再び呼び出される。 Aがグローバルな静的状態に依存している場合、これは静的状態が関数の出口から消去される前に関数が再び実行され、計算された値の半分が2回目の呼び出し。

    この場合、既に保持しているロックが実行されます。ロックが再入可能であることを認識していれば、すでにロックを保持している同じスレッドであることを認識し、私たちに教えてくれます。さもなければ、それは永久にデッドロックします - 既に保持しているロックを待っています。

    lockと​​は、スレッドがロックを保持していて、そのスレッドが同じロックを再取得しようとすると、再入可能になります。したがって、上記の擬似コードをJavaで記述すると、デッドロックは発生しません。練習帳州で

    7

    のJava並行処理 - Reentrancy means that locks are acquired on a per-thread rather than per-invocation basis.

    私はそれが正確に何を意味するのか説明しましょう。まず第一に、本質的に本質的なロックはリエントラントです。リエントラントが達成される方法は、取得されたロックの数とロックの所有者のカウンタを維持することです。カウントが0で所有者が関連付けられていない場合、ロックはどのスレッドでも保持されないことを意味します。スレッドがロックを取得すると、JVMは所有者を記録し、カウンタを1に設定します。同じスレッドが再びロックを獲得しようとすると、カウンタがインクリメントされ、所有スレッドが存在するときに同期ブロックカウンタがデクリメントされます。 countが0に達すると、再びロックが解除されます。

    簡単な例は次のようになります -

    public class Test { 
        public synchronized void performTest() { 
         //... 
        } 
    } 
    
    public class CustomTest extends Test { 
        public synchronized void performTest() { 
         //... 
         super.performTest(); 
        } 
    } 
    

    再入せずにデッドロックが存在することになります。

    enter image description here