Java:如果线程正在等待,我怎么才能通知它?

时间:2013-11-28 15:45:08

标签: java multithreading

在我的第一个Java线程中:

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

在另一个帖子中,我想发送一个通知信号:

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

但是,如果doSomeVeryLongRunningTask()方法正在运行,我不希望第二个线程被阻止。我只想通知第一个线程是否正在等待,以便第二个线程可以继续执行任务而不会被锁定。

我如何修复上述代码才能完成此任务?

5 个答案:

答案 0 :(得分:2)

他们想要修复的问题不存在。 synchronized块仅在另一个线程已经在同一对象上同步synchronized块内时才会阻塞该线程。由于doSomeVeryLongRunningTask()将在synchronized块之外被调用,因此如果另一个线程在doSomeVeryLongRunningTask()方法内,通知线程将永远不会被阻止。

但这引发了另一个问题。您似乎在想,waitnotify调用始终是配对的。情况并非如此,您可以根据需要随时拨打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机制导致内部发生的事情。唯一一个明显减慢的时刻是当多个线程到达同步块时,因此至少有一个线程必须等待。