Java 监视器:如何知道 wait(long timeout) 是由超时还是由 Notify() 结束?
首先,这几乎是以下内容的重复: 如何区分 wait(long timeout) 退出时通知或超时?
但这是一个新的后续问题。
具有此等待声明:
public final native void wait(long timeout) throws InterruptedException;
它可以通过 InterruptedException 退出,或者通过超时退出,或者因为在另一个线程中调用 Notify/NotifyAll 方法,异常很容易捕获,但是......
我的代码绝对需要知道退出是由于超时还是通知。 (将来,这段代码需要重新设计,但现在不能这样做。所以我需要知道退出等待的原因。)
具体来说,有人可以给出一个使用a的例子 ThreadLocal 布尔值仅在 notification() 上设置为 true 并且所有这些都位于现有循环内,如下所示? (这或多或少是另一个线程中接受的答案,但没有给出具体的代码示例。我对 Java 不太熟悉,所以我需要一个具体的代码示例——最好是在下面现有代码的上下文中.)
public synchronized int getLastSequenceNumber() {
while (empty) {
try {
wait(waitTimeValue);
} catch (InterruptedException e) {}
}
empty = true;
return reportedSequenceNumber;
}
public synchronized void reconcileLastSequenceNumber(int sequenceNumber) {
empty = false;
this.reportedSequenceNumber = sequenceNumber;
notifyAll();
}
布尔值“空”的用途超出了我在这里提出的具体问题。我相信我需要添加另一个布尔值来满足原始问题的建议答案。我如何将该建议的解决方案集成到上面现有的代码片段中?谢谢。
First, this is a near duplicate of:
How to differentiate when wait(long timeout) exit for notify or timeout?
But it is a new follow-on question.
Having this wait declaration:
public final native void wait(long timeout) throws InterruptedException;
It could exit by InterruptedException, or by timeout, or because Notify/NotifyAll method was called in another thread, Exception is easy to catch but...
My code absolutely needs to know if the exit was from timeout or notify. (In the future, this code needs to be redesigned, but that cannot be done now. So I need to know the reason for the exit from wait.)
Specifically, can someone give an example of using a ThreadLocal Boolean that is set to true only on notify() and where all this is inside an existing loop as shown below? (This was more or less the accepted answer in the other thread, but no specific code example was given. I'm not all that familiar with Java, so I need a specific code example -- ideally in the context of the existing code below.)
public synchronized int getLastSequenceNumber() {
while (empty) {
try {
wait(waitTimeValue);
} catch (InterruptedException e) {}
}
empty = true;
return reportedSequenceNumber;
}
public synchronized void reconcileLastSequenceNumber(int sequenceNumber) {
empty = false;
this.reportedSequenceNumber = sequenceNumber;
notifyAll();
}
the Boolean "empty" serves a purpose outside of the specific question I'm asking here. I believe I will need to add another Boolean to fulfill the suggested answer from the original question. How would I integrate that proposed solution into the existing code snippet above? Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您可能最好使用
条件
(及其await
方法)而不是内置监视器,因为await
返回一个boolean
值,指示等待是否计时出去。即使如此,您也必须提防虚假唤醒(这与对
信号
。)You might be better off using a
Condition
(and itsawait
method) rather than built-in monitors, becauseawait
returns aboolean
value indicating whether the wait timed out.And even then, you must beware of spurious wakeup (which is indistinguishable from a call to
signal
.)无论如何,您应该像当前一样使用循环,无论是否知道
wait
是否超时 - 部分原因是可能出现虚假唤醒。但是,我完全不确定您是否真的需要知道呼叫是否由于通知而退出。考虑通知在超时前一纳秒发生的情况与通知在超时后一纳秒发生的情况。两者之间有什么有用区别?从根本上讲,如果两者“大约同时”发生,则存在竞争条件。
据我所知,
wait()
确实不会让您判断调用是否超时,但它不应该 > 影响你的代码。无论如何,您应该循环并测试其他作为通知副作用的东西。老实说,我不清楚 ThreadLocal 会在哪里发挥作用 - 如果您需要能够从等待线程中分辨出来,这恰恰与您想要的相反通知线程是否已达到某个点。我认为您根本不需要额外的变量 - 您的
empty
就可以了。You should be using a loop as you currently are anyway, regardless of knowing whether the
wait
timed out - partly due to the possibility of spurious wakeups. However, I'm not at all sure that you really need to know whether the call exited due to notification or not.Consider the situation where the notification occurs a nanosecond before the timeout vs the situation where the notification occurs a nanosecond after the timeout. What's the useful difference between the two? Fundamentally there's a race condition if the two occur at "about the same time".
As far as I can tell,
wait()
really doesn't let you tell whether the call timed out or not, but it shouldn't affect your code. You should be looping and testing something else that is a side-effect of the notification anyway.It's not clear to me where a
ThreadLocal
would come into play to be honest - that's exactly the opposite of what you want if you need to be able to tell from the waiting thread whether the notifying the thread has reached a certain point. I don't think you need an extra variable at all - yourempty
is fine.没有直接的方法可以使用内置监视器 API 来报告此情况,但您可以使用显式跟踪此情况(未经测试)的新实现来替换
wait()
和其他函数:这不一定是一个好的方法当然,这样做的方法;毕竟,如果在调用
notify()
之前超时,信号条件可能会丢失。您确实应该在循环中等待,检查一些持久条件。There's no direct way to report this with the builtin monitor API, but you could replace the
wait()
and other functions with a new implementation that tracks this explicitly (untested):This isn't necessarily a good way to do this, of course; if you timeout just before
notify()
is called, the signal condition may be lost, after all. You really should be waiting in a loop, checking some persistent condition.这是基于 Jenkov 信号类的扩展版本。如果未以
Notify
结束,则会引发异常。我认为这可能会有所帮助,因为我遇到了同样的问题。This is an expanded version based on Jenkov's signal class. An exception is raised if it does not end with a
Notify
. Thought it might help as I ran into the same problem.