Java 如何区分等待(长超时)何时退出通知或超时?

Java 如何区分等待(长超时)何时退出通知或超时?,java,multithreading,wait,synchronized,notify,Java,Multithreading,Wait,Synchronized,Notify,具有此等待声明: public final native void wait(long timeout) throws InterruptedException; 它可以通过InterruptedException或超时退出,或者因为在另一个线程中调用了Notify/NotifyAll方法,所以很容易捕获异常,但 有没有办法知道退出的原因是超时还是通知 编辑: 这是一个棘手的方法,可以工作,(虽然我不喜欢它) 除非提供一些附加代码,否则无法区分两者。例如,添加一个ThreadLocalBool

具有此等待声明:

public final native void wait(long timeout) throws InterruptedException;
它可以通过InterruptedException或超时退出,或者因为在另一个线程中调用了Notify/NotifyAll方法,所以很容易捕获异常,但

有没有办法知道退出的原因是超时还是通知

编辑:

这是一个棘手的方法,可以工作,(虽然我不喜欢它)


除非提供一些附加代码,否则无法区分两者。例如,添加一个
ThreadLocal
Boolean
,仅在
notify()上设置为
true


但首先您必须确保您的逻辑需要这种区分。

在通知和超时时不会引发异常


我认为最好依靠
java.lang.concurrent
包同步对象,而不是使用
Object.wait()

这并不能完全回答问题,但它可能会解决您的问题:使用更高级别的并发机制。由于这个原因,Wait/notify通常比您想要的级别低


例如,如果您正在使用,您可以检查结果是否为空,以了解是否超时。

notify可以返回的另一个原因是:虚假唤醒。这是一件不太可能但可能发生的事情,因为在某些硬件/操作系统组合上,防止虚假唤醒非常昂贵

因此,您必须始终在循环中调用wait(),并重新检查等待的条件。在这项工作中,很容易同时检查超时


有关详细信息,我推荐《实践中的Java并发性》一书。并使用更高级别的构造,这将为您提供所有正确的信息。

无法直接判断--也就是说,您必须添加额外的代码来确定这一点。通常,当您wait()时,您正在等待以某种方式更改对象状态的事件发生,例如,通过设置布尔变量。如果是这种情况,那么您可以简单地检查该变量的状态,看看事件是否发生,或者您只是超时了。或者,您可以查看System.currentTimeMillis()的值,以查看所用时间是否大于或等于超时时间-如果大于或等于超时时间,则这可能是您可能已超时的线索(尽管这不是绝对保证)。或者,如果经过的时间小于超时时间,则您肯定没有超时。这有帮助吗?

不要使用
System.currentTimeMillis()
,而是使用
System.nanoTime()

第一种方法测量绝对时间(基于系统时钟),如果系统时间改变,可能会产生奇怪的结果。例如:如果时钟向后移动一小时,则5秒等待的持续时间可能为一小时;如果时钟向前移动,则在0秒后等待10分钟


第二个是相对时间。它总是以恒定的速度朝一个方向运行,但它没有原点。这意味着这些值只能用于测量相对时间,但可以也不应该用于确定日期。

您应该使用不等待/通知方法

最好是用带电瓶的锁


它具有wait with timeout,如果在从方法返回之前可检测到等待时间已过,则将返回false,否则为true

OP已知道不会引发异常,并希望区分超时和通知。这并没有为此提供任何有用的信息。我不认为在执行notify()时将线程本地布尔值设置为true会有什么帮助。调用notify()的线程将不是从wait()中唤醒的同一个线程。@Hernán Eche,正如我在回答中所说的,这不是绝对的保证。如果你能说出来,为什么你想确定它是否是时间?我们可以寻找一些解决方案。我也有类似的需求,在我的例子中,
信号灯
更合适
Semaphore.tryAcquire(长超时,TimeUnit)
如果超时已过,则返回
false
。除非您需要具有等待功能,否则信号量将正常工作,这是信号量公共契约不支持的。需要将条件更改为(>=):
如果((System.currentTimeMillis()-tBefore)>=超时)
您的解决方案不正确。在notify事件之后,当其他具有较高优先级的线程未运行时,调度程序将恢复该线程。这意味着,在通知之后,线程恢复之前会有一段时间间隔,如果这足以使您的条件变为真实,那么您的代码将管理超时而不是正确的行为。+1用于鼓励人们停止编写在系统时钟更新时中断的代码。但是你没有提到人们应该经常检查等待的理由是否仍然有效。
          long tBefore=System.currentTimeMillis();
          wait(TIMEOUT);
          if ((System.currentTimeMillis() - tBefore) > TIMEOUT) 
            { 
               //timeout
            }