如何区分wait(long timeout)退出是notify还是timeout?
有了这个等待声明:
public final native void wait(long timeout) throws InterruptedException;
它可以通过 InterruptedException 退出,或者通过超时退出,或者因为在另一个线程中调用 Notify/NotifyAll 方法,异常很容易捕获,但是......
有任何方法可以知道退出原因是超时还是通知?
编辑:
这是一种可行的棘手方法,(尽管我不喜欢它)
long tBefore=System.currentTimeMillis();
wait(TIMEOUT);
if ((System.currentTimeMillis() - tBefore) > TIMEOUT)
{
//timeout
}
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...
There is any way to know if the exits cause was timeout or notify?
EDIT:
This is a tricky way that could work, (although I don't like it)
long tBefore=System.currentTimeMillis();
wait(TIMEOUT);
if ((System.currentTimeMillis() - tBefore) > TIMEOUT)
{
//timeout
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
通知返回的还有一个原因:虚假唤醒。这是不太可能但有可能发生的事情,因为在某些硬件/操作系统组合上防止虚假唤醒的成本非常昂贵。
因此,您始终必须在循环中调用 wait() 并重新检查您正在等待的条件。在此工作期间,很容易同时检查超时。
详细内容推荐《Java并发实践》一书。并使用更高级别的构造,这将使这一切对您来说都是正确的。
There is one more reason that notify can return: spurious wakeup. This is an unlikely but possible thing, because preventing spurious wakeups is very expensive on some hardware/OS combinations.
Because of this you always have to call wait() in a loop and re-check the condition that you are waiting for. During this work it's easy to check for timeout at the same time.
For details I recommend the book "Java Concurrency In Practice". And using higher level constructs that will get this all correct for you.
除非您提供一些额外的代码,否则您无法区分两者。例如,通过添加仅在
notify()
上设置为true
的ThreadLocal
Boolean
但首先您必须当然你的逻辑需要这种区分。
You can't differentiate between the two unless you provide some additional code. For example by adding a
ThreadLocal
Boolean
that is set totrue
only onnotify()
But first you must make sure your logic requires this differentiation.
这并不能完全回答问题,但它可能会解决您的问题:使用更高级别的并发机制。出于这个原因和其他原因,等待/通知通常比您想要的要低级。
例如,如果您使用
BlockingQueue.poll(long, TimeUnit)
,可以通过检查结果是否为null来判断是否超时。This doesn't exactly answer the question, but it will probably solve your problem: Use higher level concurrency mechanisms. Wait/notify is usually more low-level than you'd want, for this reason among many others.
For example, if you were using
BlockingQueue.poll(long, TimeUnit)
, you could check if the result is null to know if you timed out.不要使用
System.currentTimeMillis()
,而是使用System.nanoTime()
。第一个测量绝对时间(基于系统时钟),如果系统时间更改,可能会产生奇怪的结果。例如:如果时钟向后移动一小时,则 5 秒的等待可能会持续一小时;如果时钟向前移动,则 0 秒后将等待 10 分钟。
第二个测量相对时间。它总是以匀速向一个方向运行,但它没有原点。这意味着这些值只能用于测量相对时间,但可以且不应该用于确定日期。
Don't use
System.currentTimeMillis()
, useSystem.nanoTime()
instead.The first one meassures absolute time (based on system clock) and might have curious results if the system time is changed. For example: A 5 second wait can have a duration of an hour if the clock is moved backward by an hour, or a 10 minute wait will be done after 0 seconds if the clock is moved foreward.
The second one meassures relative time. It will always run in one direction at constant speed, but it has no origin. That means that the values can only be used to meassure relative time, but can and should not be used to determine a date.
没有办法直接告诉 - 也就是说,您必须添加额外的代码来确定这一点。通常,当您 wait() 时,您正在等待以某种方式更改对象状态的事情发生 - 例如,也许通过设置布尔变量。如果是这种情况,那么您可以简单地检查该变量的状态来查看事件是否发生,或者只是超时。或者您可以查看 System.currentTimeMillis() 的值来查看经过的时间是否大于或等于超时时间 - 如果是,则表明您可能已超时(尽管这不是绝对保证) )。或者如果经过的时间小于超时时间,那么你肯定没有超时。这有帮助吗?
There's no way to tell directly - that is, you would have to add additional code to determine this. Often when you wait(), you're waiting for something to happen which changes the state of an object in some way - e.g. by setting a boolean variable, perhaps. If that's the case, then you may be able to simply check the state of that variable to see if the event occurred, or you merely timed out. Or you can look at the value of System.currentTimeMillis() to see i the elapsed time is greater than or equal to the timeout period - if it is, that would be a clue you have probably timed out (though it's not an absolute guarantee). Or if the elapsed time is less than the timeout period then you certainly have not timed out. Does that help?
您应该使用非等待/通知方法。
最好使用带有条件的 Lock https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Condition.html#await-long-java.util .concurrent.TimeUnit-
它有超时等待,如果在从方法返回之前检测到等待时间已过,则返回 false,否则返回 true
You should use not wait/notify approach.
Will be better to use Lock with Condidions https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/locks/Condition.html#await-long-java.util.concurrent.TimeUnit-
It has await with timeout and will return false if the waiting time detectably elapsed before return from the method, else true
通知和超时时不会引发异常。
我认为最好依靠
java.lang.concurrent
包同步对象,而不是使用Object.wait()
。Exception is not thrown on notify and time out.
I think it's better to rely on
java.lang.concurrent
package synchronisation objects instead of usingObject.wait()
.