Java wait()/ join():为什么这不会死锁?

jlh*_*jlh 9 java multithreading join notify wait

给出以下Java代码:

public class Test {

    static private class MyThread extends Thread {
        private boolean mustShutdown = false;

        @Override
        public synchronized void run() {
            // loop and do nothing, just wait until we must shut down
            while (!mustShutdown) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    System.out.println("Exception on wait()");
                }
            }
        }

        public synchronized void shutdown() throws InterruptedException {
            // set flag for termination, notify the thread and wait for it to die
            mustShutdown = true;
            notify();
            join(); // lock still being held here, due to 'synchronized'
        }
    }

    public static void main(String[] args) {
        MyThread mt = new MyThread();
        mt.start();

        try {
            Thread.sleep(1000);
            mt.shutdown();
        } catch (InterruptedException e) {
            System.out.println("Exception in main()");
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

运行它将等待一秒钟然后正确退出.但这对我来说意外,我预计会发生死锁.

我的推理如下:新创建的MyThread将执行run(),它被声明为'synchronized',因此它可以调用wait()并安全地读取'mustShutdown'; 在wait()调用期间,锁定被释放并在返回时重新获取,如wait()文档中所述.一秒钟后,主线程执行shutdown(),再次同步,以便在其他线程正在读取的同时不访问mustShutdown.然后它通过notify()唤醒另一个线程,并通过join()等待它的完成.

但在我看来,其他线程无法从wait()返回,因为它需要在返回之前重新获取线程对象上的锁.它不能这样做因为shutdown()在join()内部仍然保持锁定.为什么它仍能正常工作并正常退出?

Sur*_*ran 8

join()方法在内部调用wait(),这将导致释放锁(Thread对象).

请参阅下面的join()代码:

public final synchronized void join(long millis) 
    throws InterruptedException {
    ....
    if (millis == 0) {
       while (isAlive()) {
         wait(0);  //ends up releasing lock
       }
    }
    ....
}
Run Code Online (Sandbox Code Playgroud)

你的代码看到这个并且一般看不到的原因:你的代码看到这个而不是一般没有观察到的原因是因为join()方法在Thread对象本身上等待()因此放弃对Thread对象的锁定本身,并且您的run()方法也在同一个Thread对象上同步,您会看到这种意外情况.