如何使用 TimeUnit.timedWait() 而不丢失纳秒精度?

发布于 2024-08-16 06:47:03 字数 924 浏览 4 评论 0原文

我正在尝试实现Future.get(long, TimeUnit) 表示为 TimeUnit.timedWait(Object, long)

目前尚不清楚如何使用 TimeUnit.timedWait(Object, long) 来处理虚假唤醒而不丢失 TimeUnit 的纳秒部分。通常你会做这样的事情:

public V get(long timeout, TimeUnit unit)
{
  long expirationTime = new Date().getTime() + unit.toMillis(timeout);
  while (!condition)
  {
    long timeLeft = expirationTime - new Date().getTime();
    if (timeLeft <= 0)
      throw new TimeoutException();
    unit.timedWait(object, timeLeft);
  }
}

但是你会失去纳秒部分。如果每个人都简单地放弃纳秒组件,那么 TimeUnit 甚至支持纳秒并提供 TimeUnit.timedWait() 的意义何在?

I'm trying to implement Future.get(long, TimeUnit) in terms of TimeUnit.timedWait(Object, long).

It's not clear how to use TimeUnit.timedWait(Object, long) in a way that handles spurious wakeups without losing the nanosecond component of TimeUnit. Normally you'd do something like this:

public V get(long timeout, TimeUnit unit)
{
  long expirationTime = new Date().getTime() + unit.toMillis(timeout);
  while (!condition)
  {
    long timeLeft = expirationTime - new Date().getTime();
    if (timeLeft <= 0)
      throw new TimeoutException();
    unit.timedWait(object, timeLeft);
  }
}

but you lose the nanosecond component. If everyone is simply dropping the nanosecond component then what is the point of TimeUnit even supporting nanoseconds and offering TimeUnit.timedWait()?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

橙味迷妹 2024-08-23 06:47:03

在等待之前,存储您想要超时的时间。

在通知等待线程之前,设置一些共享(同步)状态信号,指示等待线程应该停止等待,因为计算已完成。

当您的线程出于某种原因从等待中唤醒时,它应该检查共享状态以查看是否应该停止等待,并且还应该检查超时到期之前还剩下多长时间。如果超时尚未到期,并且共享状态告诉您没有停止等待,那么您应该再次等待(但使用根据当前时间计算的新的较短超时)。

Before you wait, store the time at which you want to timeout.

Before you notify the waiting thread, set some shared (synchronized) state signalling that the waiting thread should stop waiting because the computation is complete.

When your thread wakes up from the wait for whatever reason it should check the shared state to see if it should stop waiting, and it should also check how long is left before the timeout expires. If the timeout has not expired, and the shared state tells does not say to stop waiting then you should wait again (but using a new shorter time out calculated from the current time).

浮华 2024-08-23 06:47:03

您问题的答案位于 Object.wait(long) 规范:

线程也可以在没有被通知、中断或超时的情况下唤醒,即所谓的虚假唤醒。虽然这种情况在实践中很少发生,但应用程序必须通过测试应导致线程被唤醒的条件来防止这种情况,并在条件不满足时继续等待。换句话说,等待应该总是在循环中发生,如下所示:(

 synchronized (obj) {
     while (<condition does not hold>)
         obj.wait(timeout);
     ... // Perform action appropriate to condition
 }

有关此主题的更多信息,请参阅 Doug Lea 的“Java 并发编程(第二版)”(Addison-Wesley,2000 年)中的第 3.2.3 节,或者Joshua Bloch 的“Effective Java 编程语言指南”(Addison-Wesley,2001 年)中的第 50 条。

The answer to your question lies in the Object.wait(long) spec:

A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this will rarely occur in practice, applications must guard against it by testing for the condition that should have caused the thread to be awakened, and continuing to wait if the condition is not satisfied. In other words, waits should always occur in loops, like this one:

 synchronized (obj) {
     while (<condition does not hold>)
         obj.wait(timeout);
     ... // Perform action appropriate to condition
 }

(For more information on this topic, see Section 3.2.3 in Doug Lea's "Concurrent Programming in Java (Second Edition)" (Addison-Wesley, 2000), or Item 50 in Joshua Bloch's "Effective Java Programming Language Guide" (Addison-Wesley, 2001).

咋地 2024-08-23 06:47:03

CountDownLatch 似乎是最简单的实现此方法的方法:

public class MutableFuture<T> implements Future<T>
{
  private final CountDownLatch done = new CountDownLatch(1);
  private T value;
  private Throwable throwable;

  public synchronized boolean isDone()
  {
    return done.getCount() == 0;
  }

  public synchronized T get(long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException
  {
    if (!done.await(timeout, unit))
      throw new TimeoutException();
    if (throwable != null)
      throw new ExecutionException(throwable);
    return value;
  }

  // remaining methods left as exercise to the reader :)
}

CountdownLatch 不容易受到虚假唤醒的影响(因为它可以在返回之前在内部检查闩锁状态)。

CountDownLatch seems to be the easiest way to implement this:

public class MutableFuture<T> implements Future<T>
{
  private final CountDownLatch done = new CountDownLatch(1);
  private T value;
  private Throwable throwable;

  public synchronized boolean isDone()
  {
    return done.getCount() == 0;
  }

  public synchronized T get(long timeout, TimeUnit unit)
    throws InterruptedException, ExecutionException, TimeoutException
  {
    if (!done.await(timeout, unit))
      throw new TimeoutException();
    if (throwable != null)
      throw new ExecutionException(throwable);
    return value;
  }

  // remaining methods left as exercise to the reader :)
}

CountdownLatch is not vulnerable to spurious wakeups (because it can check the latch state internally before returning).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文