简体   繁体   English

了解wait()和notify()方法

[英]Understanding wait() and notify() methods

I'm trying to understand how Java's wait and notify methods work. 我试图了解Java的waitnotify方法如何工作。 As per the documentation, wait() causes thread to wait for subsequent calls to notify() or notifyAll() methods but for some reason notify doesn't interrupt "waiting": 根据文档, wait()导致线程等待后续对notify()notifyAll()方法的调用,但由于某种原因, notify不会中断“ waiting”:

public static void main(String[] args) {

    Thread thread1 = new Thread(new Runnable() {
        @Override
        public void run() {
            System.out.println("thread1 is started, waiting for notify()");

            synchronized (this) {
                try {
                    wait();
                } catch (InterruptedException e) {
                    System.out.println(e.getLocalizedMessage());
                }
            }

            System.out.println("waiting is over");
        }
    });

    thread1.start();

    // unblock thread1 in 2 seconds

    try {
        Thread.sleep(2000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }

    synchronized (thread1) {
        thread1.notify();
    }
}

You need to notify the object that is being wait ed on, not the thread that is waiting. 您需要notify正在wait的对象,而不是正在wait的线程。

In your case the object wait ed on is an instance of an anonymous inner class, which is problematic because you cannot easily obtain a reference to it in order to notify it. 在您的情况下, wait对象是匿名内部类的实例,这是有问题的,因为您无法轻松地获取对该对象的引用以进行notify You could solve this by extending Thread directly: 您可以通过直接扩展Thread来解决此问题:

Thread thread1 = new Thread() {
    @Override
    public void run() {
        System.out.println("thread1 is started, waiting for notify()");

        synchronized (this) {
            try {
                wait();
            } catch (InterruptedException e) {
                System.out.println(e.getLocalizedMessage());
            }
        }

        System.out.println("waiting is over");
    }
};

Now the this (in synchronized (this) ) refers to the thread itself, and the wait is called on the thread object too. 现在this (在synchronized (this) )引用线程本身,并且也在线程对象上调用wait In this case your current call to notify should be fine, since it notifies the same object (which happens in this case to be the thread that is waiting - but just to be clear, that need not be the case). 在这种情况下,您的当前呼叫notify应该罚款,因为它会通知同一个对象( 发生在这种情况下是在等待线程-但仅仅是明确的,那不一定是这种情况)。

It isn't considered good practice to use an object for synchronisation that may also be used elsewhere; 使用对象进行同步(在其他地方也可以使用)不是一种好习惯。 instances of Thread would be an example of this, and in fact the documentation specifically advises against it: Thread实例将是一个例子,实际上文档特别建议不要这样做:

It is recommended that applications not use wait , notify , or notifyAll on Thread instances. 建议应用程序不要在Thread实例上使用waitnotifynotifyAll

Also, you should correctly handle spurious wakeup ; 另外,您应该正确处理虚假唤醒 that is, wait may return because notify / notifyAll was called elsewhere or perhaps was not even called at all. 也就是说, wait可能会返回,因为notify / notifyAll在其他地方被调用了,或者甚至根本没有被调用。 As the documentation also says : 正如文档还说的那样

A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. 线程也可以唤醒,而不会被通知,中断或超时,即所谓的虚假唤醒。 While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. 尽管在实践中这种情况很少发生,但是应用程序必须通过测试应该导致线程唤醒的条件来防范它,并在条件不满足时继续等待。 In other words, waits should always occur in loops [...] 换句话说,等待应该总是在循环中发生[...]

Therefore, your example should really use a separate variable to track whether the wakeup was intentional (due to an explicit notify ) or not. 因此,您的示例实际上应该使用一个单独的变量来跟踪唤醒是否是有意的(由于明确的notify )。

for some reason notify doesn't interrupt "waiting": 由于某些原因,notify不会中断“等待”:

@davmac's answer is correct but for posterity, there are some other ways you can do it because extending Thread and calling wait() and notify() on the Thread object is not recommended. @davmac的答案是正确的,但对于后代,您可以通过其他方法来实现,因为不建议扩展Thread并在Thread对象上调用wait()notify()

The best way would be to create a lock object. 最好的方法是创建一个锁对象。 Making your lock objects final is always a good pattern although here it is also necessary to use it in the inner class. 尽管final在内部类中使用锁对象,将锁对象定为final总是一个好的模式。

final Object lock = new Object();
Thread thread1 = new Thread(new Runnable() {
    ...
        synchronized (lock) {
            try {
                lock.wait();
            } catch (InterruptedException e) {
                // always a good pattern
                Thread.currentThread().interrupt();
                System.out.println(e.getLocalizedMessage());
            }
        }
      ...
}
...
synchronized (lock) {
    lock.notify();
}
// might as well wait for it to finish
thread1.join();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM