0

以下は、デッドロックについて私が見つけた例であり、機能します。私の質問は、どのように機能しcurrentThread()ますか? また、A と B は特にスレッドとして作成されません。つまり、次のようになります。

Deadlock d=new Deadlock();
Thread A=new Thread(d) 

コードはどのように機能しますか?

class A {
    synchronized void foo(B b) {
        String name = Thread.currentThread().getName();
        System.out.println(name + " entered A.foo");
        try {
            Thread.sleep(1000);
        } catch (Exception e) {System.out.println("A Interrupted");
        }
        System.out.println(name + " trying to call B.last()");
        b.last();
    }

    synchronized void last() {
        System.out.println("Inside A.last");
    }
}

class B {
    synchronized void bar(A a) {
        String name = Thread.currentThread().getName();
        System.out.println(name + " entered B.bar");
        try {
            Thread.sleep(1000);
        } catch (Exception e) {System.out.println("B Interrupted");
        }
        System.out.println(name + " trying to call A.last()");
        a.last();
    }
    synchronized void last() {
        System.out.println("Inside A.last");
    }
}

public class Deadlock implements Runnable {
    A a = new A();
    B b = new B();

    Deadlock() {
        Thread.currentThread().setName("MainThread");
        Thread t = new Thread(this, "RacingThread");
        t.start();
        a.foo(b); // get lock on a in this thread.
        System.out.println("Back in main thread");
    }

    public void run() {
        b.bar(a); // get lock on b in other thread.
        System.out.println("Back in other thread");
    }

    public static void main(String args[]) {
        new Deadlock();
    }
}
4

5 に答える 5

2

これはデッドロックのかなり紛らわしい例だと思います。問題に他のノイズが追加されます。

Lock次のようなオブジェクトを使用して、非常に単純な例を実現できます。

public class App {

    private static final Lock LOCKA = new ReentrantLock();
    private static final Lock LOCKB = new ReentrantLock();

    private static final class Locker1 implements Runnable {

        @Override
        public void run() {
            while (true) {
                try {
                    LOCKA.lockInterruptibly();
                    Thread.sleep(100);
                    LOCKB.lockInterruptibly();
                    System.out.println("Locker 1 Got locks");
                } catch (InterruptedException ex) {
                    return;
                }
                LOCKB.unlock();
                LOCKA.unlock();
            }
        }
    }

    private static final class Locker2 implements Runnable {

        @Override
        public void run() {
            while (true) {
                try {
                    LOCKB.lockInterruptibly();
                    Thread.sleep(100);
                    LOCKA.lockInterruptibly();
                    System.out.println("Locker 2 Got locks");
                } catch (InterruptedException ex) {
                    return;
                } finally {
                    LOCKA.unlock();
                    LOCKB.unlock();
                }
            }
        }
    }

    public static void main(String[] args) throws IOException {
        final ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.submit(new Locker1());
        executorService.submit(new Locker2());

    }
}

アプリケーションは executor で 2 つのスレッドを開始し、それらのスレッドに 2 つの runnable を呼び出させます。

Lockこれらのランナブルは、逆の順序で2 つのオブジェクトのロックを取得しようとします。

したがって、Locker1ロックLOCKAは数ミリ秒待機します。Locker2ロックLOCKBして数ミリ秒待機すると、別のロックを取得しようとします。

状況は、他のスレッドがそれを解放しないLocker1ためLOCKBLocker2待機し、永遠に待機することです。LOCKA

これは、これらのスレッドのスレッド ダンプでかなり明確に確認できます。

"pool-1-thread-1" - Thread t@8
   java.lang.Thread.State: WAITING
    at sun.misc.Unsafe.park(Native Method)
    - waiting to lock <7725204d> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) owned by "pool-1-thread-2" t@9
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:894)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1221)
    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:340)
    at com.boris.testbench.App$Locker1.run(App.java:32)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:722)

   Locked ownable synchronizers:
    - locked <7567e1fa> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

    - locked <5ad52411> (a java.util.concurrent.ThreadPoolExecutor$Worker)

"pool-1-thread-2" - Thread t@9
   java.lang.Thread.State: WAITING
    at sun.misc.Unsafe.park(Native Method)
    - waiting to lock <7567e1fa> (a java.util.concurrent.locks.ReentrantLock$NonfairSync) owned by "pool-1-thread-1" t@8
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:834)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:894)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1221)
    at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:340)
    at com.boris.testbench.App$Locker2.run(App.java:51)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:334)
    at java.util.concurrent.FutureTask.run(FutureTask.java:166)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:722)

   Locked ownable synchronizers:
    - locked <7725204d> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)

    - locked <6856c528> (a java.util.concurrent.ThreadPoolExecutor$Worker)

pool-1-thread-1が所有するロックのロックを必要としており、 が所有するロックのロックをpool-1-thread-2必要としていることがわかります。pool-1-thread-2pool-1-thread-1

この状況は永遠に続くため、デッドロックが発生します。

コードは同じ結果を達成しますが、手動で生成された 2 つのスレッドを使用する代わりに、(JVM によって生成された) アプリケーションのメイン スレッドと手動で生成された 1 つのスレッドを使用します。

また、2 つのオブジェクトではなくsynchronized2 つの s でメソッドを使用します。ObjectLock

于 2013-04-01T14:58:14.893 に答える
1

ここにいくつかの良い答えがあります(@ Ralfと@ bmorris591への+1)が、コードをもう少し説明したいと思いました。

ここには 2 つのスレッドがあります。main(...)実行され、コンストラクター"RacingThread"内から開始される「メイン」スレッド。Deadlockところで、オブジェクト コンストラクターでスレッドを開始するのは非常に悪い形式です。次のようなことをする方が良いでしょう:

  Deadlock deadlock = new Deadlock();
  new Thread(deadlock, "RacingThread").start();

また、Deadlockコンストラクター内で呼び出しますThread.currentThread().setName("MainThread");。これは、現在実行中のスレッドの名前を設定しようとしています。これは、new Deadlock(). 残念ながら、setName(...)スレッドがすでに実行されている場合、呼び出しは noop であり、何もしません。

次に、Deadlockコンストラクター内で、 as"RacingThread"で構築さthisれたRunnableandstart()が呼び出され、スレッドを fork してDeadlock.run()メソッドを呼び出させます。これには時間がかかるため、メソッドが呼び出される前にa.foo(b);行に到達する可能性が高くなります。run()

あなたabオブジェクトは、すでに指摘されているようにスレッドではありません。それらは、ロックを示すために使用されている単なるオブジェクトです。デッドロックは、メイン スレッドが呼び出しa.foo(b);を行ってから、メソッド "RacingThread"b.bar(a);内部を呼び出すために発生します。はon であり、 onであるを呼び出そうとします。 はon であり、 onであるを呼び出そうとします。それは古典的なデッドロックです。run();a.foo(...)synchronizedab.last()synchronizedbb.bar(...)synchronizedba.last()synchronizeda

これが少し役立つことを願っています。

于 2013-04-01T14:37:34.243 に答える