等待线程是否重新访问同步方法中的代码 [英] Does the waiting thread revisit the code inside synchronized method

查看:60
本文介绍了等待线程是否重新访问同步方法中的代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在从教程中了解线程同步和等待/通知结构.它指出

当调用wait时,线程释放锁并中止执行.在将来的某个时间,另一个线程将获取相同的锁并调用Object.notifyAll,通知所有在该锁上等待的线程发生了重要的事情.

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,如果在notify唤醒第一个线程时,有多个线程可以竞争该锁,则其中任何一个都可以拥有该对象上的锁.我的问题是,如果第一个线程本身重新获取了锁,它是否必须从同步方法的开头重新开始(这意味着,它在while循环检查wait()条件之前再次执行了代码)还是它只是在wait()行停顿了?

AFAIK, if there are multiple threads which can compete for the lock when the first thread is awaken by the notify, any one of them can get to own the lock on that object. My question is, if this first thread itself re-acquires the lock, does it have to start all over from the beginning of the synchronized method (which means, it again executes the code before the while loop checking wait() condition) or does it just pause at the 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,使用以下方法杀死Java进程): kill -9等),或者该方法是否正在关闭JVM的守护进程线程中运行.这里没有什么奇怪的事情.等待的线程放弃了锁定并进入休眠状态,但是并没有以某种方式停止执行该方法.

A method only gets exited when the thread executing it finishes executing its run method, whether by returning normally or having an exception be thrown that goes uncaught within that run method. The only way for your method to not get executed until one of those things above happens is for the JVM to be killed out from under you (with java.lang.System.exit, killing the java process with kill -9, etc.), or if the method is being run in a daemon thread where the JVM is shutting down. There's nothing weird going on here. The thread that waits gives up the lock and goes dormant, but it doesn't somehow leave off executing the method.

从等待调用中唤醒的线程从未到过任何地方.线程一直在等待的整个时间都处于wait方法中.在离开等待方法之前,它首先必须获取放弃的锁才能开始等待.然后,它需要重新测试需要检查的任何条件,然后才能知道是否继续等待.

The thread awakened from its call to wait never went anywhere; the whole time that the thread was waiting it was still in the wait method. Before it can leave the wait method it first has to acquire the lock that it gave up in order to start waiting. Then it needs to retest whatever condition it needs to check before it can know whether to keep on waiting.

这就是为什么受保护的块教程告诉您的原因等待必须循环执行:

This is why the guarded blocks tutorial tells you that waits have to be done in a loop:

直到另一个线程发出可能已经发生某些特殊事件的通知,直到等待调用才会返回-尽管不一定是该线程正在等待的事件:

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

注意:始终在测试等待条件的循环内调用wait.不要以为中断是针对您正在等待的特定条件,还是该条件仍然为真.

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.

(本教程使用的措词具有误导性;单词"interrupt"应为"notification".同样不幸的是,所示的教程代码在没有设置中断标志的情况下吃掉了InterruptedException,最好让InterruptedException会被这种方法抛出而根本无法捕获.)

(The wording used by the tutorial is misleading; the word "interrupt" should be "notification". Also it is unfortunate that the tutorial code shown eats the InterruptedException without setting the interrupt flag, it would be better to let the InterruptedException be thrown from this method and not catch it at all.)

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

If the thread did "start over" then this loop wouldn't be required; your code would start at the beginning of the method, acquire the lock, and test the condition being waited on.

这篇关于等待线程是否重新访问同步方法中的代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆