Java:如何仅在线程正在等待时通知它?

Java:如何仅在线程正在等待时通知它?,java,multithreading,Java,Multithreading,在第一个Java线程中,我有: while (!isDone) { try { synchronized (this) { wait(); } } catch (InterruptedException e) { e.printStackTrace(); } doSomeVeryLongRunningTask(); } 在另一个线程中,我想发送一个通知信号: synchronize

在第一个Java线程中,我有:

while (!isDone) {
    try {
        synchronized (this) {
            wait();
        } 
    } catch (InterruptedException e) {
            e.printStackTrace();
    }
    doSomeVeryLongRunningTask();
}
在另一个线程中,我想发送一个通知信号:

synchronized (thr1) {
    thr1.notify();
}
但是,如果
doSomeVeryLongRunningTask()
方法正在运行,我不希望第二个线程被阻塞。我只想在第一个线程正在等待时通知它,以便第二个线程可以继续执行它的任务而不会被锁定


如何修复上面的代码以实现此目的?

notify()调用不会阻塞。仅
wait()
块。即使没有其他线程在等待,也可以调用notify,但要确保算法正确。如果您只希望通知一次,那么在通知之后到达的另一个线程将永远等待()。仅
wait()
块。即使没有其他线程在等待,也可以调用notify,但要确保算法正确。如果您只希望通知一次,那么在通知之后到达的另一个线程将永远等待()。

似乎阻止您的程序的不是
notify()
(它永远不会阻止),而是在同一对象上同步的两个
已同步的


我认为你的问题没有解决办法。检查此链接以了解原因:

似乎阻止您的程序的不是
notify()
(它永远不会阻止),而是在同一对象上同步的两个
已同步的


我认为你的问题没有解决办法。检查此链接以了解原因:

建议的模式是使用notifyAll(),并让所有等待的线程在每次收到通知时以及开始第一次等待之前检查其唤醒条件。

建议的模式是使用notifyAll()并让所有等待线程在每次收到通知时以及在开始第一次等待之前检查其唤醒条件。

现代Java中的synchronized大约与
--i
一样快,因为这是由于硬件
compareAndSet
机制在内部发生的事情。唯一明显变慢的时刻是当多个线程到达同步块时,因此至少有一个线程必须等待。

现代Java中的同步大约与
--i
一样快,因为这是由于硬件
比较数据集
机制而在内部发生的事情。唯一明显变慢的时刻是多个线程到达同步块,因此至少有一个线程必须等待。

您要修复的问题不存在<代码>同步
块仅当另一个线程已在同一对象上的
同步
块中时,才会阻止线程。由于您的
doSomeVeryLongRunningTask()
将在
synchronized
块外部调用,因此如果另一个线程在
doSomeVeryLongRunningTask()方法内部,通知线程将永远不会被阻止

但这引发了另一个问题。您似乎在想,
wait
notify
调用总是成对的。情况并非如此,您可以随时调用
notify
,而无需任何人接听。
wait
调用也可能是“虚假”返回,即没有明显的原因。因此,您需要定义另一个“硬条件”,该条件由
synchronized
块内修改和检查的状态定义

例如,在
thr1
变量中实例所在的类中,可以定义
布尔
标志:

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();
}

这样,您的通知代码仍然不会被阻止(至少在很长一段时间内不会被阻止),但等待的线程将在一个循环周期内等待至少一个通知发生。

您要修复的问题不存在<代码>同步
块仅当另一个线程已在同一对象上的
同步
块中时,才会阻止线程。由于您的
doSomeVeryLongRunningTask()
将在
synchronized
块外部调用,因此如果另一个线程在
doSomeVeryLongRunningTask()方法内部,通知线程将永远不会被阻止

但这引发了另一个问题。您似乎在想,
wait
notify
调用总是成对的。情况并非如此,您可以随时调用
notify
,而无需任何人接听。
wait
调用也可能是“虚假”返回,即没有明显的原因。因此,您需要定义另一个“硬条件”,该条件由
synchronized
块内修改和检查的状态定义

例如,在
thr1
变量中实例所在的类中,可以定义
布尔
标志:

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();
}

这样,您的通知代码仍然不会被阻止(至少在很长一段时间内不会被阻止),但等待的线程将在一个循环周期内等待至少一个通知。

notify()不会被阻止,但必须在thrd1上同步。有没有更好的方法来解决这个问题呢?notify()不会阻塞,但必须在thrd1上进行同步。有没有更好的方法来解决这个问题?我基本上遇到的是生产者-消费者问题,消费者有时会非常缓慢,我不想阻止生产者完成其他任务。这是否有助于潜在地建议一种替代方法,以避免在这种c语言中,制作者在
synchronized(thrd1)
等待的情况