我正在阅读教程中的线程同步和等待/通知构造.它说明了这一点
当调用wait时,线程释放锁并暂停执行.在将来的某个时间,另一个线程将获取相同的锁并调用Object.notifyAll,通知等待该锁的所有线程发生了重要的事情.
在第二个线程释放锁之后的一段时间,第一个线程重新获取锁并通过从等待调用返回来恢复.
AFAIK,如果有多个线程可以在第一个线程被唤醒时竞争锁定,那么notify它们中的任何一个都可以拥有该对象的锁定.我的问题是,如果第一个线程本身重新获取锁,它是否必须从synchronized方法的开头全部开始(这意味着它再次在while循环检查wait()条件之前执行代码)或者它只是暂停wait()在线?
// 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 Code Online (Sandbox Code Playgroud)
只有当执行它的线程完成执行其run方法时才会退出一个方法,无论是正常返回还是抛出在该run方法中未被捕获的异常.在上面发生上述事情之一之前,你的方法没有被执行的唯一方法是让JVM从你身下被杀掉(使用java.lang.System.exit,使用kill -9杀死java进程等)或者,如果该方法正在JVM正在关闭的守护程序线程中运行.这里没有什么奇怪的事情发生.等待的线程放弃锁定并进入休眠状态,但它不会以某种方式停止执行该方法.
从等待的呼叫唤醒的线程从未到过任何地方; 线程等待的整个时间仍然在等待方法中.在它离开等待方法之前,首先必须获得它放弃的锁以便开始等待.然后它需要重新测试它需要检查的任何条件才能知道是否继续等待.
这就是为什么受保护的块教程告诉你等待必须在循环中完成:
在另一个线程发出可能发生某些特殊事件的通知之前,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!");
}
Run Code Online (Sandbox Code Playgroud)
注意:始终在测试等待条件的循环内调用wait.不要假设中断是针对您正在等待的特定条件,或者条件仍然是真的.
(本教程使用的措辞具有误导性;"中断"一词应该是"通知".同样不幸的是,显示的教程代码在没有设置中断标志的情况下吃了InterruptedException,最好让InterruptedException从中抛出这种方法并没有完全抓住它.)
如果线程确实"重新开始",则不需要此循环; 您的代码将从方法的开头开始,获取锁定,并测试正在等待的条件.
| 归档时间: |
|
| 查看次数: |
1862 次 |
| 最近记录: |