我正在阅读有关线程同步和等待/通知结构的内容tutorial http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html。它指出
当调用 wait 时,线程释放锁并暂停执行。在将来的某个时间,另一个线程将获取相同的锁并调用 Object.notifyAll,通知所有等待该锁的线程发生了重要的事情。
在第二个线程释放锁一段时间后,第一个线程重新获取锁并通过从 wait 调用返回来恢复。
AFAIK,如果有多个线程可以在第一个线程被唤醒时竞争锁notify
,其中任何一个都可以拥有该对象上的锁。我的问题是,如果第一个线程本身重新获取锁,它是否必须从同步方法的开头重新开始(这意味着,它再次在 while 循环检查 wait() 条件之前执行代码)或者它只是暂停在wait()
line?
// Does the waiting thread come back here while trying to own the
// lock (competing with others)?
public synchronized notifyJoy() {
// Some code => Does this piece of code gets executed again then in case
// waiting thread restarts its execution from the method after it is notified?
while (!joy) {
try {
// Does the waiting thread stay here while trying to re-acquire
// the lock?
wait();
} catch(InterruptedException e) {}
}
// Some other code
}
仅当执行该方法的线程完成执行其 run 方法时,方法才会退出,无论是正常返回还是抛出在该 run 方法中未捕获的异常。你的方法的唯一途径not直到上述事情之一发生时才会执行,即 JVM 从您的下面被杀死(使用 java.lang.System.exit,使用 Kill -9 杀死 java 进程等),或者该方法正在运行在 JVM 正在关闭的守护线程中。这里没有什么奇怪的事情发生。等待的线程放弃锁并进入休眠状态,但它不会以某种方式停止执行该方法。
从 wait 调用中唤醒的线程永远不会去任何地方;在线程等待的整个过程中,它仍然处于 wait 方法中。在它离开 wait 方法之前,它首先必须获取它放弃的锁才能开始等待。然后,它需要重新测试需要检查的任何条件,然后才能知道是否继续等待。
这就是为什么受保护的块教程 http://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html告诉你等待必须在循环中完成:
wait 的调用不会返回,直到另一个线程发出可能发生某些特殊事件的通知 - 尽管不一定是该线程正在等待的事件:
public synchronized void guardedJoy() {
// This guard only loops once for each special event, which may not
// be the event we're waiting for.
while(!joy) {
try {
wait();
} catch (InterruptedException e) {}
}
System.out.println("Joy and efficiency have been achieved!");
}
注意:始终在循环内调用 wait 来测试正在等待的条件。不要假设中断是针对您正在等待的特定条件的,或者条件仍然为真。
(本教程使用的措辞具有误导性;“中断”一词应该是“通知”。此外,不幸的是,所示的教程代码在没有设置中断标志的情况下吃掉了 InterruptedException,最好让 InterruptedException 从这个方法根本没有捕获它。)
如果线程确实“重新开始”,那么就不需要这个循环;您的代码将从方法的开头开始,获取锁,并测试正在等待的条件。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)