Като се има предвид следният 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(). Защо все още работи и излиза правилно?