1

次のコードがデッドロックを引き起こさないのはなぜですか?

マルチスレッドプログラミングについての私の限られた理解から、getBar1()が呼び出されるsharedBufferと「ロック」されるため、メソッドがを呼び出そうとするとgetBar2()、スレッドは待機する必要がありますsharedBuffer(これはそれ自体で保持されます!)。つまり、has(およびreleased )getBar2()になるまで戻ることはできません。ただ一方で、帰ってくるのを待っているので帰れません。getBar1()sharedBuffergetBar1()getBar2()

==>デッドロック。(しかし、実際にはそうではないので、私は混乱しています)

...
Foo sharedBuffer = new Foo();

Bar1 getBar1()
{
     Bar1 bar1;
     synchronized (sharedBuffer)
     {
            bar1 = sharedBuffer.getBar1();
            if (bar1 == null)
                bar1 = new Bar1(sharedBuffer, getBat2());
            sharedBuffer.setBar1(bar1);
     }
     return bar1;
}

Bar2 getBar2()
{
    Bar2 bar2;
    synchronized (sharedBuffer)
    {
        bar2 = sharedBuffer.getBar2();
        if (bar2 == null)
            bar2 = new Bar2();
    }
    return bar2;
}
...
4

3 に答える 3

3

Javaのモニターは再帰的です。つまり、同じスレッドが同じロックを複数回取得できます。

JLSから(§17.1同期):

スレッドtは、特定のモニターを複数回ロックする場合があります。ロックを解除するたびに、1回のロック操作の効果が逆転します。

于 2013-03-15T16:44:36.820 に答える
0

デッドロックは、並行操作が2つ以上のリソースを異なる順序でロックしようとしたときに発生し、両方が他方によってロックされたリソースを待機してスタックします。

たとえば、スレッドT1とT2はリソースR1とR2で同期します。

  • T1はR1で同期します。
  • スケジューラーはT2を実行する必要があると判断します
  • T2はR2で同期します。
  • T2はR1で同期を試みます。T1がロックを解除するまで待機する必要があります。
  • スケジューラーは、T2が実行を継続できないことを認識しているため、T1の実行を許可します
  • T1はR2で同期を試みます。T2がロックを解除するまで待機する必要があります。
  • どちらのスレッドも続行できません

ここで行っているのは基本的な同期であり、一度に1つのオブジェクトにのみアクセスを許可しますsharedBuffer

于 2013-03-15T16:44:50.437 に答える
0

実際にはロックが1つしかないため、デッドロックは発生しません。どちらの関数でも、sharedBufferをロックしています。最初のスレッドがgetBar1()を呼び出すと、sharedBufferをロックします。同じスレッドがgetBar2()を呼び出すと、同期されたブロックにヒットし、すでにロックされているため、ロックに入るだけです。

デッドロックを引き起こしたい場合は、ロックする2つの異なる値を使用してください。次に、タイミングが適切に並んでいる場合にのみ表示されます。デッドロックを強制する場合は、最初のスレッドが2番目のスレッドがロックを取得するのに十分な時間スリープしていることを確認してください。

これがデッドロックするコードです...(テストされていない、prollyにはタイプミスがあります)。別のスレッドがロックを必要とするスレッドとは異なるロックを持っているため、これは機能するはずです。

public class Deadlock extends Thread
{
    private Deadlock other;
    private String name;

    public static void main(String[] args)
    {
        Deadlock one = new Deadlock("one");
        Deadlock two = new Deadlock("two");
        one.setOther(two);
        two.setOther(one);
        one.start();
        two.start();
    }

    public setOther(Deadlock other){ this.other = other; }

    public void run() {
       deadlock();
    }

    public synchronized deadlock() {
         System.out.println("thread " + this.name + " entering this.deadlock()");
         sleep(1000); // adjust as needed to guarantee deadlock
         System.out.println("thread " + this.name + " calling other.deadlock()");
         other.deadlock(this.name);
         System.out.println(name + " - deadlock avoided!");
    }
}
于 2013-03-15T16:47:46.667 に答える