【问题标题】:Java concurrent - spurious wakeups and wait(timeout)Java 并发 - 虚假唤醒和等待(超时)
【发布时间】:2016-04-01 18:12:48
【问题描述】:

我了解到,在等待对象时,条件应该放在循环中,而不是放在单个 if condition 中。这样做的原因之一是为了避免可能发生的各种虚假唤醒呼叫。

例如:

synchronized (obj) {
    while (condition is false) {
        obj.wait(5 * 1000);
    }
    ... do something ...
}

但是,我只想等待 5 秒钟让线程收到通知。在上面的代码中,线程等待 5 秒。但在那之后,如果条件仍然为假,我们再次等待。如果我有以下情况,情况就不是这样了:

synchronized (obj) {
    if (condition is false) {
        obj.wait(5 * 1000);
    }
    ... do something ...
}

但这与我们应该使用循环而不是单个 if 条件的准则相矛盾!

这是怎么解决的?

【问题讨论】:

  • 你可能会在进入循环之前记住当前时间,如果在唤醒时经过给定的时间,则使条件为真。
  • 当然。好主意!
  • 我回答了我自己的问题。希望它是正确的。
  • 在散文中,条件仅指布尔值,假设它可以无限期地等待直到收到通知。超时基本上是第二个条件。
  • @Dave 很好,但我建议ReentrantLock 和它的.tryAcquire(time, timeUnit) 这样做。如果您只需要阻塞当前线程一段时间,请使用Thread.sleep()

标签: java concurrency


【解决方案1】:

我通常是这样处理的:

long timeout = ....;
synchronized(obj) {
  long start = System.currentTimeMillis();
  while(!condition && (timeout > 0)) {
    obj.wait(timeout);
    long now = System.currentTimeMillis();
    timeout -= (now - start);
    start = now;
  }
}

【讨论】:

    【解决方案2】:

    回答我自己的问题,这可能有效:

    synchronized (obj) {
        for (long time = System.currentTimeMillis() + timeout; !condition && System.currentTimeMillis() < time; ) {
            obj.wait(time - System.currentTimeMillis());
        }
        if (condition) {
            ... do something ...
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2011-12-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-06-16
      • 1970-01-01
      相关资源
      最近更新 更多