【问题标题】:Java: How to distinguish between spurious wakeup and timeout in wait()Java:如何区分 wait() 中的虚假唤醒和超时
【发布时间】:2011-12-31 23:30:43
【问题描述】:

这是一个线程正在等待 notify() 或超时的情况。这里添加了一个while循环来处理虚假唤醒。

boolean dosleep = true;
while (dosleep){
    try {
        wait(2000);
        /**
         * Write some code here so that
         * if it is spurious wakeup, go back and sleep.
         * or if it is timeout, get out of the loop. 
         */

    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

在这种情况下,如何区分虚假唤醒和超时?如果是虚假唤醒,我需要回去等待。如果是超时,我需要退出循环。

我可以很容易地识别 notify() 的情况,因为我将在 notify() 调用时将 dosleep 变量设置为 false。

编辑:由于嵌入式项目的要求,我正在使用 1.4 java 版本。我不能使用Condition,因为它仅在 1.5 之后可用。

提前致谢。

【问题讨论】:

  • Bringer128 有一个合理的解决方案,但是,我质疑你为什么要这样做。中断通常不是“虚假唤醒”,它是中断和停止进程的信号。
  • 这与中断无关。 “虚假唤醒”随时可能出现。如果它在我进入等待()之后同时出现,那么我不想退出循环。我需要确保在退出循环之前至少等待timeout 时间
  • 我明白了。你没有被打断,但是其他一些线程正在调用 notify(),或者更有可能是 notifyAll(),你会被唤醒。

标签: java multithreading wait


【解决方案1】:

你可以这样做:

boolean dosleep = true;
long endTime = System.currentTimeMillis() + 2000;
while (dosleep) {
    try {
        long sleepTime = endTime - System.currentTimeMillis();
        if (sleepTime <= 0) {
            dosleep = false;
            } else {
            wait(sleepTime);
        }
    } catch ...
}

这在 Java 1.4 中应该可以正常工作,它会确保您的线程至少休眠 2000 毫秒。

【讨论】:

    【解决方案2】:

    如果你想区分这两种情况,你需要跟踪你的超时时间。

    long timeout = 2000;
    long timeoutExpires = System.currentTimeMillis() + timeout;
    while(dosleep) {
      wait(timeout);
      if(System.currentTimeMillis() >= timeoutExpires) {
        // Get out of loop
        break;
      }
    }
    

    也就是说,denis 建议使用 Condition 类是更好的方法。

    【讨论】:

    • 此代码在虚假唤醒发生后再次等待整个超时,这是不正确的。 Cameron Skinner 的回答是正确的,并且也向后兼容 JDK v4(而 Denis.Solonenko 的回答也是正确的,它使用 java.concurrency API,因此需要 JDK v5+)。这就是我的话题。
    • 不要使用 System.currentTimeMillis() 而是使用某种形式的单调时间,因为当系统时钟改变时这很容易出现异常。 stackoverflow.com/questions/351565/…
    • 正如 Jiri Patera 所指出的,这个例子本身就有缺陷。此外,除了“条件类”实际上是一个接口之外,Condition 的 JavaDoc 清楚地说明了An implementation is free to remove the possibility of spurious wakeups but it is recommended that applications programmers always assume that they can occur and so always wait in a loop。 Cameron Skinner 有唯一正确的答案。
    【解决方案3】:

    我相信Locks 和Condition 在这种情况下会更好地满足您的需求。请检查 Condition.awaitUntil() 的 javadocs - 它有一个使用示例

    【讨论】:

    • 由于嵌入式项目要求,我使用的是 1.4 java 版本。恐怕 Condition 仅在 1.5 之后可用。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-16
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多