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

有这个等待声明:

public final native void wait(long timeout) throws InterruptedException; 

它可以通过InterruptedException或超时退出,或者因为在另一个线程中调用Notify / NotifyAll方法,Exception很容易捕获但是……

有什么方法可以知道退出原因是超时还是通知?

编辑:

这是一个可行的棘手方式,(虽然我不喜欢它)

  long tBefore=System.currentTimeMillis(); wait(TIMEOUT); if ((System.currentTimeMillis() - tBefore) > TIMEOUT) { //timeout } 

除非您提供一些额外的代码,否则无法区分这两者。 例如,通过添加仅在notify()上设置为trueThreadLocal Boolean

但首先,你必须确保你的逻辑需要这种差异化。

通知可以返回的另一个原因是:虚假唤醒。 这是不太可能但可能的事情,因为在一些硬件/ OS组合上防止虚假唤醒是非常昂贵的。

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

有关详细信息,我建议使用“Java Concurrency In Practice”一书。 并使用更高级别的结构,这将使您的所有正确。

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

例如,如果您使用的是BlockingQueue.poll(long, TimeUnit) ,则可以检查结果是否为null,以确定您是否超时。

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

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

第二个是相对时间。 它将始终以恒定速度在一个方向上运行, 但它没有原点 。 这意味着这些值只能用于确保相对时间,但可以而且不应该用于确定日期。

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

通知和超时不会抛出exception。

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

你应该使用not wait / notify方法。

最好使用Lock with Condidions https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Condition.html#await-long-java.util.concurrent.TimeUnit-

它等待超时,如果在从方法返回之前可检测到等待时间,则返回false,否则返回true