给定以下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()");
}
}
}
运行此代码会等待一秒钟然后正常退出。但这对我来说是意外的,我期望会发生死锁。
我的推理如下:新创建的MyThread将执行run()方法,该方法声明为“同步”,因此它可以调用wait()方法并安全地读取“mustShutdown”;在wait()调用期间,锁被释放并在返回时重新获取,如wait()方法的文档中所述。一秒钟后,主线程执行shutdown()方法,该方法再次同步,以便不同时访问mustShutdown变量。然后通过notify()唤醒另一个线程,并通过join()等待其完成。
但是,在我看来,另一个线程永远无法从wait()中返回,因为它需要在返回之前重新获取线程对象上的锁。它无法这样做,因为shutdown()在join()内部仍然持有锁。为什么它仍然能够正常工作并正确退出呢?