我有一个在我的程序后台运行的线程,并检测何时发生截止日期(由程序开头的用户输入设置)。我已在while
循环中使用sleep(1000)
方法实现了此功能。
这一切都运行正常,但我想将其从使用sleep(1000)
更改为使用wait()
和notifyAll()
以与我的其余代码保持一致,并将其更改为警报实时发生,而不是滞后一段时间,直到线程重新唤醒。
这是我目前拥有的
//Retrieve current date and time...
Calendar now = Calendar.getInstance();
//deadline not yet reached
while(now.before(deadline))
{
try
{
//wait a second and try again
sleep(1000);
}
catch (InterruptedException intEx)
{
//Do nothing.
}
//Update current date and time...
now = Calendar.getInstance();
//run loop again
}
////////////////////////////
///alert user of deadline///
////////////////////////////
我尝试将其更改为使用wait()
,但没有成功。任何人都可以看到一种改变现有代码的方法来实现我提到的方法吗?
提前致谢, 标记
答案 0 :(得分:4)
所以这个问题是,如何使用wait
来表达sleep
。如果要使用wait,则必须使用两个线程。使用ScheduledExecutorService
(Tutorial)。
ScheduledExecutorService executor = newSingleThreadScheduledExecutor();
这可以完成一次并重复使用。否则你必须关闭执行程序。
我们将使用现代Instant
框架(java.time)中的Tutorial将截止日期设置为x
分钟。
final Instant deadline = Instant.now().plus(x, ChronoUnit.MINUTES);
接下来,我们要安排一个任务,以便我们的线程在x分钟内唤醒。
while(Instant.now().isBefore(deadline)){
synchronized(deadline){
executor.schedule(
()->{
synchronized(deadline){
deadline.notifyAll();
}
},
Duration.between(Instant.now(),deadline).toMillis(),
TimeUnit.MILLISECONDS
);
deadline.wait();
}
}
这是一个循环,以防万一有虚假的清醒。它重新提交任务,以防万一有虚假的清醒,同时另一个任务完成,并且在线程再次调用wait之前没有唤醒线程。
这上面有点舌头。真的,如果你刚刚使用了以下内容,那么它似乎更像是实时的''。
long diff = deadline.getTimeInMillis()-now.getTimeInMillis();
if(diff>0)
Thread.sleep(diff);
答案 1 :(得分:1)
来自oracle文档page
public final void wait(long timeout)
throws InterruptedException
导致当前线程等待,直到另一个线程调用此对象的notify()方法或notifyAll()方法,或者已经过了指定的时间量。
前提条件: 当前线程必须拥有此对象的监视器。
线程也可以在没有被通知,中断或超时的情况下唤醒,即所谓的虚假唤醒。虽然这在实践中很少发生,但应用程序必须通过测试应该导致线程被唤醒的条件来防范它,并且如果条件不满足则继续等待。换句话说,等待应该总是出现在循环中,如下所示:
synchronized (obj) {
while (<condition does not hold>)
obj.wait(timeout);
... // Perform action appropriate to condition
}
答案 2 :(得分:0)
使用wait(long timeout)方法。