次の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()");
}
}
}
これを実行すると、1秒間待機してから、適切に終了します。しかし、それは私には予想外です。ここでデッドロックが発生することを期待しています。
私の推論は次のとおりです。新しく作成されたMyThreadはrun()を実行します。これは、「同期」として宣言されているため、wait()を呼び出して、「mustShutdown」を安全に読み取ることができます。そのwait()呼び出し中に、wait()のドキュメントで説明されているように、ロックが解放され、戻ったときに再取得されます。1秒後、メインスレッドはshutdown()を実行します。これは、他のスレッドによる読み取りと同時にmustShutdownにアクセスしないように再度同期されます。次に、notify()を介して他のスレッドをウェイクアップし、join()を介してその完了を待ちます。
しかし、私の意見では、他のスレッドがwait()から戻ることはできません。これは、戻る前にスレッドオブジェクトのロックを再取得する必要があるためです。shutdown()はjoin()内でロックを保持しているため、これを行うことはできません。それでも機能し、正しく終了するのはなぜですか?