notify 和 notifyAll 的区别



(一)先看一个 notify发生死锁的例子:

http://blog.csdn.net/tayanxunhua/article/details/20998449


(本文虽是转载,不过也加入了一些个人观点)
JVM多个线程间的通信是通过 线程的锁、条件语句、以及wait()、notify()/notifyAll组成。
下面来实现一个启用多个线程来循环的输出两个不同的语句:
package   com.tyxh.block;

class   OutTurn {
     private   boolean   isSub   =   true ;
     private   int   count   = 0;

     public   synchronized   void   sub() {
            try   {
                while   (! isSub   ) {
                    this .wait();
             }
             System.   out .println( "sub ---- "   +   count );
                isSub   =   false   ;
                this .notify();
         }   catch   (Exception e) {
             e.printStackTrace();
         }
            count ++;

    }

     public   synchronized   void   main() {
            try   {
                while   ( isSub   ) {
                    this .wait();
             }
             System.   out .println( "main (((((((((((( "   +   count );
                isSub   =   true   ;
                this .notify();
         }   catch   (Exception e) {
             e.printStackTrace();
         }
            count ++;
    }
}
package   com.tyxh.block;

public   class   LockDemo {
     public   static   void   main(String[] args) {
            // System.out.println("lock");

            final   OutTurn ot =   new   OutTurn();

            for   ( int   j = 0; j < 100; j++) {

                new   Thread( new   Runnable() {

                    public   void   run() {
                         // try {
                         // Thread.sleep(10);
                         // } catch (InterruptedException e) {
                         // e.printStackTrace();
                         // }
                         for   ( int   i = 0; i < 5; i++) {
                          ot.sub();
                      }
                 }
             }).start();

                new   Thread( new   Runnable() {

                    public   void   run() {
                         // try {
                         // Thread.sleep(10);
                         // } catch (InterruptedException e) {
                         // e.printStackTrace();
                         // }
                         for   ( int   i = 0; i < 5; i++) {
                          ot.main();
                      }
                 }
             }).start();
         }

    }
}

解释一下原因:
     OutTurn类中的sub和main方法都是同步方法,所以多个调用sub和main方法的线程都会处于阻塞状态,等待一个正在运行的线程来唤醒它们。下面分别分析一下使用notify和notifyAll方法唤醒线程的不同之处:
     上面的代码使用了notify方法进行唤醒,而notify方法只能唤醒一个线程,其它等待的线程仍然处于wait状态,假设调用sub方法的线程执行完后(即 System.   out  .println( "sub ---- "   count  ) 执行完之后),所有的线程都处于等待状态,此时在sub方法中的线程执行了isSub=false语句后又执行了notify方法,这时如果唤醒的是一个sub方法的调度线程,那么while循环等于true,则此唤醒的线程也会处于等待状态,此时所有的线程都处于等待状态,那么也就没有了运行的线程来唤醒它们,这就发生了死锁。
     如果使用notifyAll方法来唤醒所有正在等待该锁的线程,那么所有的线程都会处于运行前的准备状态(就是sub方法执行完后,唤醒了所有等待该锁的状态,注:不是wait状态),那么此时,即使再次唤醒一个sub方法调度线程,while循环等于true,唤醒的线程再次处于等待状态,那么还会有其它的线程可以获得锁,进入运行状态。

     总结:notify方法很容易引起死锁,除非你根据自己的程序设计,确定不会发生死锁,notifyAll方法则是线程的安全唤醒方法。



notify和notifyAll的区别:

notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法。

void notify(): 唤醒一个正在等待该对象的线程。
void notifyAll(): 唤醒所有正在等待该对象的线程。
两者的最大区别在于:
     notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争。
     notify他只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其他同样在等待被该对象notify的线程们,当第一个线程运行完毕以后释放对象上的锁,此时如果该对象没有再次使用notify语句,即便该对象已经空闲,其他wait状态等待的线程由于没有得到该对象的通知,继续处在wait状态,直到这个对象发出一个notify或notifyAll,它们等待的是被notify或notifyAll,而不是锁。  

 

 





(二)再看一个例子:
https://www.zhihu.com/question/37601861

作者:Alex Wang
链接:https://www.zhihu.com/question/37601861/answer/94679949
来源:知乎
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

还是直接上代码:
public class WaitAndNotify {
public static void main(String[] args) {
        Object co = new Object();
        System.out.println(co);

        for (int i = 0; i < 5; i++) {
            MyThread t = new MyThread("Thread" + i, co);
            t.start();
        }

try {
            TimeUnit.SECONDS.sleep(2);
            System.out.println("-----Main Thread notify-----");
            synchronized (co) {
                co.notify();
            }

            TimeUnit.SECONDS.sleep(2);
            System.out.println("Main Thread is end.");

        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

static class MyThread extends Thread {
private String name;
        private Object co;

        public MyThread(String name, Object o) {
this.name = name;
            this.co = o;
        }

@Override
        public void run() {
            System.out.println(name + " is waiting.");
            try {
synchronized (co) {
co.wait();
                }
                System.out.println(name + " has been notified.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}


运行结果
java.lang.Object@1540e19d
Thread1 is waiting.
Thread2 is waiting.
Thread0 is waiting.
Thread3 is waiting.
Thread4 is waiting.
-----Main Thread notify-----
Thread1 has been notified.
Main Thread is end.

将其中的那个notify换成notifyAll运行结果
Thread0 is waiting.
Thread1 is waiting.
Thread2 is waiting.
Thread3 is waiting.
Thread4 is waiting.
-----Main Thread notifyAll-----
Thread4 has been notified.
Thread2 has been notified.
Thread1 has been notified.
Thread3 has been notified.
Thread0 has been notified.
Main Thread is end.

运行环境jdk8结论
notify唤醒一个等待的线程notifyAll唤醒所有等待的线程


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值