【问题标题】:Java wait specific interval notify not workingJava等待特定间隔通知不起作用
【发布时间】:2012-09-04 12:10:31
【问题描述】:

代码sn-p:

class Counter implements Runnable {
    Object s = new Object();

    @Override
    public void run() {
        try {
            synchronized (s) {
                s.wait(10000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //...do Something
    }

    public void stopCounter() {
        synchronized (s) {
            s.notifyAll();
        }   
    }
}

无论我是否调用 stopCounter,...do Something 代码总是仅在等待间隔之后执行。即使在通知之后它仍然等待 10 秒。

【问题讨论】:

  • 在调用 stopCounter() 之前是否更改了变量 s
  • 由于虚假唤醒,等待的调用几乎总是处于循环中。基本上,当您为同一个对象调用 notify 或 notifyAll 时,wait 总是会返回。但它也可能出于任何原因或根本没有原因返回。所以你需要某种信号(通常是一个易失的布尔变量)和一个循环。每次等待返回时,检查变量,如果它没有达到所需的值,请再次等待。
  • 如果您的目标是通常等待 10 秒,但有时会提前唤醒,那么最好使用 Thread.sleep(没有虚假唤醒)和 Thread.interrupt(当您希望睡眠线程醒来)。
  • 不,我正在使用相同的计数器实例。

标签: java wait intervals notify


【解决方案1】:

我无法从您的示例中看出您要达到的目标。如果要尝试替换某种轮询,请考虑在 Java 5 中发布的BlockingQueue 接口。既然它出现了,我就不需要等待/通知了。它使用起来要简单得多,并且 java 在幕后为您完成了等价的等待/通知。

【讨论】:

    【解决方案2】:

    这取决于您使用它的方式。我刚刚通过添加一个主要方法并运行它来尝试它,看起来等待/通知机制工作正常,而不是你描述的方式。请自行尝试:

    public static void main(String[] args) {
      Counter c = new Counter();
      new Thread(c).start();
      try {
        Thread.sleep(1000);
      } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
      c.stopCounter();
    }
    

    【讨论】:

      【解决方案3】:

      我的猜测是您在 Counter 类的不同实例上调用了 runstopCounter 方法。因此,它们使用不同的监视器(您的 s = new Object()),并且停止调用不会通知其他计数器。

      例如,这将与您描述的行为类似(除非您得到虚假唤醒):

      public static void main(String[] args) throws InterruptedException {
          Counter c = new Counter();
          new Thread(c).start();
          Thread.sleep(200);
          new Counter().stopCounter();
      }
      
      static class Counter implements Runnable {
      
          Object s = new Object();
      
          @Override
          public void run() {
              try {
                  System.out.println("in");
                  synchronized (s) {
                      s.wait(10000);
                  }
                  System.out.println("out");
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              //...do Something
          }
      
          public void stopCounter() {
              synchronized (s) {
                  s.notifyAll();
              }
              System.out.println("notified");
          }
      }
      

      【讨论】:

      • 不,我使用的是同一个实例,我也执行了上面的代码。立即打印“通知”,但 10 秒后打印“出”
      • 我建议您展示所有相关代码,以便我们重现您观察到的行为。
      • 我执行了您粘贴的代码,我希望在打印“notified”之后应该打印“out”。但它会在 10 秒后打印出来。它会立即为您打印出来吗?
      • 不,out 在我的机器上 10 秒后打印,这是我的代码的预期行为。
      • @Rakesh 抱歉,现在没时间聊天。但是可能发生的情况是,您在调用 wait 之前调用 notify(不一定按照程序顺序,但这是您的机器在各个线程中排序指令的方式) - 所以一旦您调用 wait,因为 notify 事件已经消失,它一直等到超时。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-30
      相关资源
      最近更新 更多