我试图了解Java wait
和notify
方法的工作原理。根据文档,wait()
会导致线程等待后续调用notify()
或notifyAll()
方法但由于某种原因notify
不会中断"等待& #34;:
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();
}
}
答案 0 :(得分:4)
您需要notify
正在wait
的对象,而不是正在等待的线程。
在你的情况下,对象wait
是一个匿名内部类的实例,这是有问题的,因为你不能轻易获得它的引用,以便notify
它。您可以通过直接扩展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");
}
};
现在this
(在synchronized (this)
中)引用了线程本身,并且在线程对象上也调用了wait
。在这种情况下,您对notify
的当前调用应该没问题,因为它通知同一个对象(在这种情况下发生是等待的线程 - 但是要清楚,那个不一定是这样的。)
使用可能在其他地方使用的同步对象并不是一种良好的做法; Thread的实例就是这样的一个例子,事实上documentation特别反对它:
建议应用程序不要在
wait
个实例上使用notify
,notifyAll
或Thread
。
另外,你应该正确处理虚假唤醒;也就是说,wait
可能会返回,因为notify
/ notifyAll
在其他地方被调用,或者甚至根本不被调用。作为文档also says:
线程也可以在没有被通知,中断或超时的情况下唤醒,即所谓的虚假唤醒。虽然这在实践中很少发生,但应用程序必须通过测试应该导致线程被唤醒的条件来防范它,并且如果条件不满足则继续等待。换句话说,等待应始终出现在循环[...]
中
因此,您的示例应该使用单独的变量来跟踪唤醒是否是故意的(由于明确的notify
)。
答案 1 :(得分:1)
由于某种原因,通知不会中断“等待”:
@ davmac的答案是正确的,但对于后代,还有其他一些方法可以做到这一点,因为在Thread
对象上扩展wait()
并调用notify()
和Thread
是不推荐。
最好的方法是创建一个锁对象。制作锁定对象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();