【问题标题】:Java - use wait() method until specific time reachedJava - 使用 wait() 方法直到达到特定时间
【发布时间】:2016-03-13 20:34:11
【问题描述】:

我有一个线程在我的程序后台运行并检测截止日期(由用户在程序开始时输入设置)何时发生。我已经在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(),但没有成功。任何人都可以看到改变现有代码以实现我提到的方法的方法吗?

提前致谢, 标记

【问题讨论】:

  • notifyAll 在哪里被调用?你为什么不只睡你需要的秒数,而不是任意的 1000 秒?
  • notifyAll() 目前没有被调用,因为还没有 wait() 调用。目前它每秒钟检查一次,因为截止时间输入为一分钟,而我只是每秒检查一次。我想改用 wait() 以使其更准确@matt
  • wait 和 sleep 都使用 OS 来执行等待,一个并不比另一个更准确。事实上,等待不太准确,因为它可以令人惊讶地醒来,而睡眠则不会
  • 顺便说一句,除非您知道可以安全地这样做,否则您不应忽略异常。你不应该犯这样的错误;我不知道如何处理异常,所以我会假装它没有发生。
  • Re,我想将它从使用 sleep(1000) 更改为使用 wait() 和 notifyAll() 为什么? Thread.sleep(n)o.wait(n) 用于解决不同的问题。您可以使用 wait(n) 作为 sleep(n) 的替代品,但您唯一要做的就是迷惑、惹恼和疏远试图阅读您的代码的其他程序员。原因是,程序员希望函数的 name 告诉他们你想要完成的事情。如果他们看到wait(n),那么他们希望在某处找到notify()。但如果他们看到sleep(n),他们就知道不必费心去看了。

标签: java multithreading wait


【解决方案1】:

所以这个问题是,我如何使用wait 来表现得像sleep。如果要使用等待,则必须使用两个线程。使用ScheduledExecutorService (Tutorial)。

 ScheduledExecutorService executor = newSingleThreadScheduledExecutor();

这可以一次性完成并重复使用。否则你必须关闭执行器。

我们将使用现代java.time 框架(Tutorial) 中的Instant 将截止日期设置为未来的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();
    }
}

它处于一个循环中,以防万一出现虚假唤醒。它重新提交任务,以防万一出现虚假唤醒,同时另一个任务完成并且在线程再次调用等待之前没有唤醒线程。

上面这句话有点说不过去。真的,如果您只使用以下内容,它看起来会更“实时”。

long diff = deadline.getTimeInMillis()-now.getTimeInMillis();
if(diff>0)
    Thread.sleep(diff);

【讨论】:

    【解决方案2】:

    来自 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
     }
    

    【讨论】:

      【解决方案3】:

      使用wait(long timeout) 方法。

      【讨论】:

      • 您好,这个方法是如何工作的?它会一直等到达到最后期限,然后退出 while 循环吗?
      • @marcuthh 它确实说明了它在 javadoc 中的作用。请注意,这是用于使用锁。如果你没有锁定一个对象,那么在它上面wait 是没有意义的。
      猜你喜欢
      • 2011-05-30
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多