简体   繁体   English

Java:仅在线程处于等待状态时,如何通知线程?

[英]Java: How can I notify a thread only if it is waiting?

In a first Java thread I have: 在第一个Java线程中,我有:

while (!isDone) {
    try {
        synchronized (this) {
            wait();
        } 
    } catch (InterruptedException e) {
            e.printStackTrace();
    }
    doSomeVeryLongRunningTask();
}

In another thread, I want to send a notify signal: 在另一个线程中,我想发送一个通知信号:

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

However, if the doSomeVeryLongRunningTask() method is running, I don't want the second thread to get blocked. 但是,如果doSomeVeryLongRunningTask()方法正在运行,则我不希望第二个线程被阻塞。 I only want to notify the first thread if it is waiting so that the second thread can continue it tasks without getting locked. 我只想通知第一个线程正在等待,以便第二个线程可以继续执行它的任务而不会被锁定。

How might I fix the code above to accomplish this? 我如何修复上面的代码来完成此任务?

They problem you want to fix does not exist. 您要修复的问题不存在。 synchronized blocks will block the thread only if another thread is already inside a synchronized block synchronizing on the same object . 仅当另一个线程已经在同一对象上进行synchronized块中时, synchronized块才会阻塞该线程。 Since your doSomeVeryLongRunningTask() will be called outside the synchronized block the notifying thread will never get blocked if the other thread is inside the doSomeVeryLongRunningTask() method. 由于您的doSomeVeryLongRunningTask()将在synchronized块外部调用,因此如果另一个线程在doSomeVeryLongRunningTask()方法内部,则通知线程将永远不会被阻塞。

But this raises another problem. 但这提出了另一个问题。 You seem to be thinking, that wait and notify invocations are always paired. 您似乎在想, waitnotify调用总是成对出现的。 This is not the case, you may call notify as often as you wish without anyone listening to it. 事实并非如此,您可以在不听任何人的情况下,根据需要notify致电notify It might be also the case that a wait invocation returns “spuriously”, ie for no apparent reason. 也可能是wait调用“虚假”返回,即没有明显的原因。 You therefore need to define another “hard condition” which is defined by a state that is modified and checked inside the synchronized block. 因此,您需要定义另一个“硬条件”,该条件由在synchronized块内部修改和检查的状态定义。

Eg inside the class whose instance you have in your thr1 variable, you can define a boolean flag: 例如,在您的实例中包含您的thr1变量的类内,您可以定义一个boolean标志:

boolean condition;

Then you modify you waiting method like this: 然后,您修改等待方法,如下所示:

while(!isDone) {
  try {
    synchronized(this) {
      while(!condition) wait();
      if(isDone) break;// skip doSomeVeryLongRunningTask()
      condition=false;
    }
  } catch(InterruptedException e) {
    e.printStackTrace();
  }
  doSomeVeryLongRunningTask();
}

And the notifying code to: 通知代码可以:

synchronized(thr1) {
  thr1.condition=true;
  thr1.notify();
}

This way your notifying code still won't get blocked (at least never for a significant time) but the waiting thread will wait for at least one notification to happen within one loop cycle. 这样,您的通知代码仍然不会被阻塞(至少在相当长的时间内不会被阻塞),但是等待线程将等待至少一个通知在一个循环周期内发生。

It seems what is blocking your program is not the notify() (it doesn't block ever) but the two synchronized blocks that are synchronizing on the same object. 似乎阻塞您的程序的不是notify() (它永远不会阻塞),而是在同一个对象上synchronized的两个synchronized块。

I don't think there is a workaround to what you ask. 我认为您的要求没有解决方法。 Check this link to know why: http://javarevisited.blogspot.com/2011/05/wait-notify-and-notifyall-in-java.html 检查此链接以了解原因: http : //javarevisited.blogspot.com/2011/05/wait-notify-and-notifyall-in-java.html

The notify() call doesn't block. notify()调用不会阻塞。 Only wait() blocks. wait()块。 You can call notify even if there isn't another thread waiting, but then make sure your algorithm is correct. 即使没有其他线程在等待,您也可以调用notify,但是请确保您的算法正确。 If you expect to notify only once, then another thread arriving after the notify will wait() forever. 如果您希望只通知一次,则在通知之后到达的另一个线程将永远等待()。

建议的模式是使用notifyAll()并让所有等待线程在每次通知它们时都检查它们的唤醒条件,并且在开始第一个Wait之前。

The synchronized in modern Java is about as fast as --i , because this is about what is internally happening thanks to hardware compareAndSet mechanisms. 在现代Java中,同步大约与--i一样快,因为这与内部发生的事情有关,这要归功于硬件compareAndSet机制。 The only moment this slows down noticeably, is when more than one thread is arriving at the synchronized block and therefore at least one has to wait. 唯一显着减慢的时刻是在多个线程到达同步块时,因此至少有一个线程必须等待。

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

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