java – 等待线程是否重新访问synchronized方法中的代码

我正在阅读有关tutorial中的线程同步和等待/通知结构的信息.它说明了这一点

When wait is invoked, the thread releases the lock and suspends execution. At some future time, another thread will acquire the same lock and invoke Object.notifyAll, informing all threads waiting on that lock that something important has happened.

Some time after the second thread has released the lock, the first thread reacquires the lock and resumes by returning from the invocation of wait.

AFAIK,如果有多个线程可以在第一个线程被通知唤醒时竞争锁,那么它们中的任何一个都可以拥有该对象的锁.我的问题是,如果第一个线程本身重新获取锁,它是否必须从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方法时才会退出一个方法,无论是正常返回还是抛出在该run方法中未被捕获的异常.在上面发生上述事情之一之前,你的方法没有被执行的唯一方法是让JVM从你身下被杀掉(使用java.lang.System.exit,使用kill -9杀死java进程等)或者,如果该方法正在JVM正在关闭的守护程序线程中运行.这里没有什么奇怪的事情发生.等待的线程放弃锁定并进入休眠状态,但它不会以某种方式停止执行该方法.

从等待的呼叫唤醒的线程从未到过任何地方;线程等待的整个时间仍然在等待方法中.在它离开等待方法之前,首先必须获得它放弃的锁以便开始等待.然后它需要重新测试它需要检查的任何条件才能知道是否继续等待.

这就是为什么the guarded blocks tutorial告诉你等待必须在循环中完成的原因:

The invocation of wait does not return until another thread has issued a notification that some special event may have occurred — though not necessarily the event this thread is waiting for:

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!");
}

Note: Always invoke wait inside a loop that tests for the condition being waited for. Don’t assume that the interrupt was for the particular condition you were waiting for, or that the condition is still true.

(本教程使用的措辞具有误导性;“中断”一词应该是“通知”.同样不幸的是,显示的教程代码在没有设置中断标志的情况下吃了InterruptedException,最好让InterruptedException从中抛出这种方法并没有完全抓住它.)

如果线程确实“重新开始”,则不需要此循环;您的代码将从方法的开头开始,获取锁定,并测试正在等待的条件.

转载注明原文:java – 等待线程是否重新访问synchronized方法中的代码 - 代码日志