【问题标题】:Java - when to use notify or notifyAll? [duplicate]Java - 何时使用 notify 或 notifyAll? [复制]
【发布时间】:2011-02-19 12:46:58
【问题描述】:

为什么java.lang.Object 有两个通知方法——notifynotifyAll?似乎notifyAll 至少完成了notify 所做的所有事情,那么为什么不一直使用notifyAll 呢?如果使用notifyAll 而不是notify,程序是否仍然正确,反之亦然?是什么影响了这两种方法的选择?

【问题讨论】:

  • 这个问题的答案就在 StackOverflow 上:Java notify() vs. notifyAll()
  • 对该问题的公认答案暗示了一个答案 - 区别在于性能,使用 notifyAll 唤醒无法执行实际工作的线程只是性能问题。所以我认为这回答了这个问题 - notifyAll 总是正确的 - 只是没有那么高效。
  • 从 Java 5(2004 年)开始,添加了一个新的并发库。 (这个库实际上更老了)我建议你使用这些类,我不鼓励使用 notify 或 notifyAll。

标签: java multithreading concurrency synchronization


【解决方案1】:

两个典型的例子。

假设您有一个生产者线程和一个消费者线程。生产者产生的每个“数据包”都应该被消费者消费。消费者将一些东西放入队列中,然后调用notify()(只允许一个消费者通过来处理一个“数据包”。)

假设您希望在冗长的流程完成后收到通知。您需要哔声和屏幕更新。该进程执行notifyAll() 来通知哔哔线程和屏幕更新线程。

【讨论】:

    【解决方案2】:

    根据notify 的JavaDoc:

    唤醒在该对象的监视器上等待的单个线程。如果有任何线程正在等待该对象,则选择其中一个被唤醒。该选择是任意的,并由实施自行决定。线程通过调用其中一个等待方法在对象的监视器上等待。

    如果您的应用程序使用例如队列来放置项目,然后有许多工作线程将项目从队列中拉出,这可能会很有用。当一个项目准备好时,你可以调用notify 来唤醒一个工人来处理这个项目。诚然,这个例子有点做作——在 Java 中可能有更好的方法来实现它——但你明白了。

    【讨论】:

      【解决方案3】:
        //contribute By E.Thulasiram and Team
         class AA extends Thread{
      AA a;
      public void get(AA a){
          this.a=a;
      }
      public void run(){
          System.out.println("one");
          synchronized (a) {
              try{
                  a.wait();
                  System.out.println("one wake up");
                  this.wait();
              }catch(Exception e){
                  System.out.println(e);
              }
          }
      }
           }
           class BB extends Thread{
      AA a;
      public void get(AA a){
          this.a=a;
      }
      public void run(){
          System.out.println("two");
          synchronized (a) {
              try{
                  a.wait();
                  System.out.println("two wake up");
              }catch(Exception e){
                  System.out.println(e);
              }
          }
       }
           }
           class CC extends Thread{
      AA a;
      public void get(AA a){
          this.a=a;
      }
      public void run(){
          synchronized (a) {
              a.notifyAll();
              System.out.println("NotifyAll");
          }
      }
          } 
          class DD{
      public static void main(String args[]){
          AA a=new AA();
          BB b=new BB();
          CC c=new CC();
          a.get(a);
          a.start();
          b.get(a);
          b.start();
          c.get(a);
          c.start();
      }
          }
      

      【讨论】:

      • 这是一个/为什么它不稳定的例子,对吗?可悲的是,没有描述......
      【解决方案4】:

      不同之处在于notify() 只重击在当前线程上等待的一个线程。对于大多数生产者/消费者和委托等待应用程序,这是使用的正确方法。此外,如果只有一个其他线程在当前线程上等待,则无需通知多个等待线程。

      相比之下,notifyAll() 重击所有在当前线程上等待的其他线程。这在每个(相关的)睡眠线程都必须做某事的情况下更有用,例如响应通知线程遇到的致命或高重要性事件。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-17
        • 1970-01-01
        • 2016-12-26
        • 1970-01-01
        • 2013-07-10
        相关资源
        最近更新 更多