如何使用 TimeUnit.timedWait() 而不丢失纳秒精度?
我正在尝试实现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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在等待之前,存储您想要超时的时间。
在通知等待线程之前,设置一些共享(同步)状态信号,指示等待线程应该停止等待,因为计算已完成。
当您的线程出于某种原因从等待中唤醒时,它应该检查共享状态以查看是否应该停止等待,并且还应该检查超时到期之前还剩下多长时间。如果超时尚未到期,并且共享状态告诉您没有停止等待,那么您应该再次等待(但使用根据当前时间计算的新的较短超时)。
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).
您问题的答案位于 Object.wait(long) 规范:
线程也可以在没有被通知、中断或超时的情况下唤醒,即所谓的虚假唤醒。虽然这种情况在实践中很少发生,但应用程序必须通过测试应导致线程被唤醒的条件来防止这种情况,并在条件不满足时继续等待。换句话说,等待应该总是在循环中发生,如下所示:(
有关此主题的更多信息,请参阅 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:
(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).
CountDownLatch 似乎是最简单的实现此方法的方法:
CountdownLatch 不容易受到虚假唤醒的影响(因为它可以在返回之前在内部检查闩锁状态)。
CountDownLatch seems to be the easiest way to implement this:
CountdownLatch is not vulnerable to spurious wakeups (because it can check the latch state internally before returning).