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

时间:2010-08-03 14:51:34

标签: java multithreading wait synchronized notify

有这个等待声明:

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
            }

7 个答案:

答案 0 :(得分:15)

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

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

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

答案 1 :(得分:12)

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

例如,如果您使用BlockingQueue.poll(long, TimeUnit),则可以检查结果是否为空,以了解您是否超时。

答案 2 :(得分:10)

除非您提供一些额外的代码,否则无法区分这两者。例如,仅在ThreadLocal上添加Boolean设置为true的{​​{1}}

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

答案 3 :(得分:4)

请勿使用System.currentTimeMillis(),而是使用System.nanoTime()

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

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

答案 4 :(得分:2)

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

答案 5 :(得分:1)

通知和超时时不会抛出异常。

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

答案 6 :(得分:0)

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

将Lock与条件https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Condition.html#await-long-java.util.concurrent.TimeUnit-结合使用

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