notify 和 notifyAll 的区别


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

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

(本文虽是转载,不过也加入了一些个人观点)
JVM多个线程间的通信是通过 线程的锁、条件语句、以及wait()、notify()/notifyAll组成。
下面来实现一个启用多个线程来循环的输出两个不同的语句:
packagecom.tyxh.block;
classOutTurn {
privatebooleanisSub=true;
privateintcount= 0;
publicsynchronizedvoidsub() {
try{
while(!isSub) {
this.wait();
}
System.out.println("sub ---- "+count);
isSub=false;
this.notify();
}catch(Exception e) {
e.printStackTrace();
}
count++;
}
publicsynchronizedvoidmain() {
try{
while(isSub) {
this.wait();
}
System.out.println("main (((((((((((( "+count);
isSub=true;
this.notify();
}catch(Exception e) {
e.printStackTrace();
}
count++;
}
}
packagecom.tyxh.block;
publicclassLockDemo {
publicstaticvoidmain(String[] args) {
// System.out.println("lock");
finalOutTurn ot =newOutTurn();
for(intj = 0; j < 100; j++) {
newThread(newRunnable() {
publicvoidrun() {
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
for(inti = 0; i < 5; i++) {
ot.sub();
}
}
}).start();
newThread(newRunnable() {
publicvoidrun() {
// try {
// Thread.sleep(10);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
for(inti = 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唤醒所有等待的线程

notify 与 nofityall,notify造成死锁实践

优质内容筛选与推荐>>
1、struts 2读书笔记-----Convention插件与“约定”支持
2、使用刀锋助手找回自信的游戏玩家
3、action,webaction,mode,controller
4、panle 闪烁 通过windowsApi
5、Linux下的shell编程(三)BY 四喜三顺


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号





    联系我们

    欢迎来到TinyMind。

    关于TinyMind的内容或商务合作、网站建议,举报不良信息等均可联系我们。

    TinyMind客服邮箱:support@tinymind.net.cn