public class Reader extends Thread {
   Calculator calc;
   public Reader(Calculator calc){
      this.calc = calc;
   }
   
   public void run(){
      synchronized (calc) {
         try{
            System.out.println(Thread.currentThread().getName()+"Waiting for notify....");
            calc.wait();
            System.out.println(Thread.currentThread().getName()+"After wait...");
         }catch(Exception c){}
      }
   }
   
   public static void main(String[] args) {
      Calculator calculator = new Calculator();
      (new Reader(calculator)).start();
      (new Reader(calculator)).start();
      (new Reader(calculator)).start();
      (new Reader(calculator)).start();
      (new Reader(calculator)).start();
      (new Reader(calculator)).start();
      calculator.start();
   }}
class Calculator extends Thread{
   int total;
   
   public void run(){
      synchronized(this){
         for(int i=0;i<3;i++){
            total += i;
            System.out.println(total);
         }
         notify();
         System.out.println("after notifyAll...");
      }
   }
}这段代码,notify只通知 了一个。为何所有的wait都执行了??

解决方案 »

  1.   

    很奇怪,解释不了,下面这段代码才是正常现象    public static void main(String[] args) throws InterruptedException {
           Calculator calculator = new Calculator();
           (new Reader(calculator)).start();
           (new Reader(calculator)).start();
           (new Reader(calculator)).start();
           (new Reader(calculator)).start();
           (new Reader(calculator)).start();
           (new Reader(calculator)).start();
           Thread.sleep(1000);
    //       calculator.start();
           synchronized(calculator) {
               calculator.notifyAll();           
           }
        }
      

  2.   

    抱歉,上面那句是notifyAll了,请参照下面这个main    public static void main(String[] args) throws InterruptedException {
           Calculator calculator = new Calculator();
           (new Reader(calculator)).start();
           (new Reader(calculator)).start();
           (new Reader(calculator)).start();
           (new Reader(calculator)).start();
           (new Reader(calculator)).start();
           (new Reader(calculator)).start();
           Thread.sleep(1000);
    //       calculator.start();
           synchronized(calculator) {
               calculator.notify();           
           }
        }
      

  3.   

    没太看懂你的问题,不过标题不厚道,虽然我不是高手,虽然20分不算高分,但是
    你上面那个程序一切正常,你把你自己加的notify()去掉。然后多运行几次可能会明白,给一个线程类加锁,还启动这个线程类,和给普通类加锁不太一样
      

  4.   

    先解释一下为何出现这个现象:
    线程Reader1-6,和线程Calculator。
    当main线程进入到第一句: (new Reader(calculator)).start();
    线程Reader1获得锁,开始运行,
    这时JVM可能调度Reader2,3,4,5,6线程开始运行,但它们都没有获得锁,所以都block了。
    这时,Reader1运行继续运行,然后,显然wait了,JVM可能运行线程Calculator,当执行到notify(),发现只有Reader1在wait,所以只有把它叫醒,Reader1执行完毕,JVM会选择那些还block在该锁上的线程,继续运行。2,notify和notifyAll的区别
    JDK文档说的很清楚,关键是何时使用哪个。多数时候,使用notifyAll,这样比较安全。
      

  5.   

    Geek618  这个说的真是我没语言了这里线程wait了以后  他的锁就释放掉了   哪里还会什么block啊这几个线程程序执行到wait  是无限制的等待     等待他main函数中calculator.start()这里运行线程去notify唤醒本任务  因为他是用同一个对象去wait 所以全部都会唤醒
      

  6.   


    public class Reader extends Thread {
       Calculator calc;
       public Reader(Calculator calc){
          this.calc = calc;
       }
       
    1,   public void run(){
    2,      synchronized (calc) {
    3,         try{
    4,            System.out.println(Thread.currentThread().getName()+"Waiting for notify....");
    5,            calc.wait();
    6,            System.out.println(Thread.currentThread().getName()+"After wait...");
    7,         }catch(Exception c){}
    8      }
       }看上面这个程序,当线程Reader1在执行第5句之前,JVM是有可能把CPU调度给其它线程的,如果这时把CPU调度给Reader2线程,Reader2线程在执行第2句时,需要获得calc变量所指向的锁,由于无法获得,就只能被block(阻挡)了。
      

  7.   

    因为同一个对象在不同线程被锁所以notify一次所有线程解锁?
      

  8.   

    没有让人信服的答案。
    百度多少也只是那一句俗语:
    notify通知一个。
    notifyAll通知全部。
    现在活生生的例子放在面前的时候,为什么没人可以合理解释呢。
      

  9.   

    Geek618说得似乎有些道理,不过我把这个执行了一次,并不是你说的那样!
    他这个锁定的是calculator这个对象,而整个程序中,只有一个calculator实例,那么这里不同的Reader访问calculator,会不会出现一些被锁住的情况呢?
    按照例子,似乎不会出现这样,那这个怎么解释呢?synchronized锁住的究竟是什么?
      

  10.   

    是的,按理就wait就只能由notify来唤醒。其它的一概不行。
    可是问题在这里,谁允许那帮wait()自己活过来了??
    是JVM这么聪明,说就你们几个还没执行了。赶紧执行吧
      

  11.   

    线程对象和其他对象是不一样的,如果你锁的是普通对象,或者是一个没有被启动的线程对象,notify一次只有一个线程被激活,你可以试试不用calculator.start();用calculator.run()是不是能得到这样的结果,线程在start之后在结束run方法过程后是会有一些特殊处理的类似于激活所有的线程的操作,如果没有记错这部分是native的不是java实现的
      

  12.   

    你这样用个后被启动线程对象当锁,就算你不执行你那句notify结果基本上一样
      

  13.   

    yktd26  说的没错  这里的问题根本不是notify的问题    你main 方法里面最后执行的   calculator.start();
    你换成  calculator.run()   那铁定你会出现你想要的结果 唤醒其中一个线程  
     
    我的意思是 执行这个方法calculator.start()其实就代表了 , 线程激活  ,  他是同一个对象执行的wait()
    所以全部会唤醒 这里主要就是 在最后执行了calculator.start()这个方法  第一行开始是线程创建 执行此方法就是激活线程 他的wait()状态 就不存在了     大概就是这样   其实具体是不是这样说 我也拿不定    但是确实是这么一回事就是了   楼主不知道是不是做的测试才这么写的代码  按照正常的写法   你做的一些对线程的操作 还是要放在一个类里面的好  Reader 里面再写一个方法去唤醒 这样的问题就可以避免了
      

  14.   

    改成run的结果:
    Thread-1Waiting for notify....
    Thread-2Waiting for notify....
    Thread-3Waiting for notify....
    Thread-4Waiting for notify....
    Thread-5Waiting for notify....
    0
    1
    3
    after notifyAll...
    notify sleep
    Thread-1After wait...   //只唤醒了第一个,并且使整个进程处于阻塞状态。
    Thread-6Waiting for notify....
      

  15.   

    换成run 的结果本来就是只唤醒一个啊   
      

  16.   

    18楼,不要不是高手装高手。
    我现在想说,那么为什么呢?
    start 和 run 区别在哪里?
      

  17.   

    将Calculator中run方法里面的notify()去掉,结果也是会唤醒其他多个线程的,也就是说其他线程根本不是notify()方法唤醒的。原因应该在native方法中,期待高手解答
      

  18.   


    先申明我不是高手  
    我给你解释了几次  可能我水平真有问题  没说的你明白  我觉得已经说的差不多了  没必要给你说JDK里面具体是怎么实现的吧  说实话我也不知道就是了
    耐心给你解释反倒成了累赘了   
    最后回答你上面问题一次
    start()方法是启动一个线程 里面没错是调用的native方法  具体里面做了什么 我没看过 
    run()方法 是有java虚拟机调用的
    也就是说线程start()没有直接调用run()方法   我上面已经说了  start()是做一个激活线程操作 
    java虚拟机执行run()方法才是具体的操作内容
     
    还有你问的为什么是这样的这个问题  我想说JDK里面就是这样的   你有办法吗?
      

  19.   

    再补一下
    前提:
    1.在main()后面用了对象calc.start() 或者  calc.run() 
    2.开始的时候是用同一个对象调用calc.wait();如果你只是显示的调用calc.run() 方法  那他执行calc.notify()一次  就是上面我说的肯定唤醒一个  那就是普遍大家认为的notify唤醒一个线程  notifyAll唤醒全部线程而 calc.start() 启动了线程 把你 同一个对象调用的calc.wait(); 方法 激活了   因为start()方法是要激活这个线程的  你先把他wait()掉了   那么start()方法还怎么启动线程啊  那么jdk肯定是要把wait()状态去掉  才能启动线程啊 我实在是没办法说清楚了   只能说这些了   你还是要问为什么  那我只能撞墙了    别太专牛角尖了
      

  20.   

    可归根结底与notify的思想相抵触的。
    或者说那锁能自己解开吗?
      

  21.   

    1.可归根结底与notify的思想相抵触的
        如果不这么做 , 你先wait()了那么start() 难道不让他启动?  他们的思想是要先保证启动一个线程是优先的吧
        人家的思想是这样啊
    2.或者说那锁能自己解开吗?
        你wait()的时候就已经放弃了那把同步锁了  只是让你这个任务对象calc等待执行 挂起
      

  22.   

    现在成讯打印如下:
    after notifyAll...
    Thread-1After wait...
    Thread-6After wait...
    Thread-5After wait...
    Thread-4After wait...
    Thread-3After wait...
    Thread-2After wait...
    我们 去掉 notify()方法,看看。如下class Calculator extends Thread{
       int total;
       
       public void run(){
          synchronized(this){
             for(int i=0;i<3;i++){
                total += i;
                System.out.println(total);
             }
             //notify();  去掉
             System.out.println("after notifyAll...");
          }
       }
    }则打印结果如下:after notifyAll...
    Thread-6After wait...
    Thread-5After wait...
    Thread-4After wait...
    Thread-3After wait...
    Thread-2After wait...
    Thread-1After wait...比较两次打印结果变化,楼主写的那个notify()确实只notify了一个(就是thread1), 而其他几个thread到底是被谁,如何被唤醒的,目前本人还不好解释,只能猜测:某个线程结束时,自己调用了一个this.notifyAll();   这也可以解释前面讨论的调run()和start()的不同表现。
      

  23.   

    start启动线程
    run只是在主线程里运行一个一般的函数
      

  24.   

    无意中进来看到这些....
    真是说什么的都有啊,你的这个程序逻辑挺简单的啊
     (new Reader(calculator)).start();
          (new Reader(calculator)).start();
          (new Reader(calculator)).start();
          (new Reader(calculator)).start();
          (new Reader(calculator)).start();
          (new Reader(calculator)).start();
    以上线程执行自己的run方法后都进入了calculator对象的等待池。
      calculator.start();
    执行后,从等待池中随机唤醒一个,之后calculator的run方法结束,并且交出了锁,这个时候重新和唤醒的线程竞争对象锁。