在我的第一个Java线程中:
while (!isDone) {
try {
synchronized (this) {
wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
doSomeVeryLongRunningTask();
}
在另一个帖子中,我想发送一个通知信号:
synchronized (thr1) {
thr1.notify();
}
但是,如果doSomeVeryLongRunningTask()
方法正在运行,我不希望第二个线程被阻止。我只想通知第一个线程是否正在等待,以便第二个线程可以继续执行任务而不会被锁定。
我如何修复上述代码才能完成此任务?
答案 0 :(得分:2)
他们想要修复的问题不存在。 synchronized
块仅在另一个线程已经在同一对象上同步的synchronized
块内时才会阻塞该线程。由于doSomeVeryLongRunningTask()
将在synchronized
块之外被调用,因此如果另一个线程在doSomeVeryLongRunningTask()
方法内,通知线程将永远不会被阻止。
但这引发了另一个问题。您似乎在想,wait
和notify
调用始终是配对的。情况并非如此,您可以根据需要随时拨打notify
,而无需任何人收听。也可能是wait
调用“虚假地”返回,即没有明显原因。因此,您需要定义另一个“硬条件”,该条件由在synchronized
块内修改和检查的状态定义。
E.g。在您的thr1
变量中具有其实例的类中,您可以定义boolean
标记:
boolean condition;
然后你修改你这样的等待方法:
while(!isDone) {
try {
synchronized(this) {
while(!condition) wait();
if(isDone) break;// skip doSomeVeryLongRunningTask()
condition=false;
}
} catch(InterruptedException e) {
e.printStackTrace();
}
doSomeVeryLongRunningTask();
}
通知代码:
synchronized(thr1) {
thr1.condition=true;
thr1.notify();
}
这样你的通知代码仍然不会被阻止(至少从来没有被阻止),但是等待的线程将等待在一个循环周期内发生至少一个通知。
答案 1 :(得分:1)
似乎阻止你的程序的不是notify()
(它不会阻塞),而是同一个对象上同步的两个synchronized
块。
我认为你的要求没有解决方法。请查看此链接以了解原因:http://javarevisited.blogspot.com/2011/05/wait-notify-and-notifyall-in-java.html
答案 2 :(得分:0)
notify()
来电不会阻止。只有wait()
个阻止。即使没有其他线程在等待,您也可以调用notify,但请确保您的算法正确无误。如果您希望只通知一次,那么在通知之后到达的另一个线程将永远等待()。
答案 3 :(得分:0)
建议的模式是使用notifyAll()AND让所有等待线程在每次通知和开始第一次Wait之前检查它们的唤醒条件。
答案 4 :(得分:0)
现代Java中的同步速度与--i
一样快,因为这是由于硬件compareAndSet
机制导致内部发生的事情。唯一一个明显减慢的时刻是当多个线程到达同步块时,因此至少有一个线程必须等待。