notify和notifyAll有什么区别

  1 /*
  2  * 文件名:NotifyDeadLockDemo.java
  3  * 版权:Enmuser Technologies Co.,Ltd. Copyright 2016-2018
  4  * 描述:<描述>
  5  * 修改人:enmuser
  6  * 修改时间:2018年2月24日
  7  * 修改单号:<修改单号>
  8  * 修改内容:<修改内容>
  9  *
 10  */
 11 package notify.deadLock;
 12
 13 /**
 14  * <一句话功能描述>
 15  * <功能详细描述>
 16  * @author 朱洪昌
 17  * @date 2018年2月24日
 18  * @version 1.0
 19  */
 20 class OutTurn
 21 {
 22     private boolean isSub = true;
 23     private int count = 0;
 24
 25     public synchronized void sub()
 26     {
 27         try
 28         {
 29             while(!isSub)
 30             {
 31                 this.wait();
 32             }
 33             System.out.println("sub --- " + count);
 34             isSub = false;
 35             this.notify();
 36         }
 37         catch (InterruptedException e)
 38         {
 39             e.printStackTrace();
 40         }
 41         count++;
 42     }
 43
 44     public synchronized void main()
 45     {
 46         try
 47         {
 48             while(isSub)
 49             {
 50                 this.wait();
 51             }
 52             System.out.println("main --- " + count);
 53             isSub = true;
 54             this.notify();
 55         }
 56         catch (InterruptedException e)
 57         {
 58             e.printStackTrace();
 59         }
 60         count++;
 61     }
 62 }
 63 public class NotifyDeadLockDemo
 64 {
 65     public static void main(String[] args)
 66     {
 67         final OutTurn outTurn = new OutTurn();
 68         for (int i = 0; i < 100; i++)
 69         {
 70             new Thread(new Runnable()
 71             {
 72
 73                 @Override
 74                 public void run()
 75                 {
 76                     for (int j = 0; j < 5; j++)
 77                     {
 78                         outTurn.sub();
 79                     }
 80
 81                 }
 82             }).start();
 83
 84             new Thread(new Runnable()
 85             {
 86
 87                 @Override
 88                 public void run()
 89                 {
 90                     for (int j = 0; j < 5; j++)
 91                     {
 92                         outTurn.main();
 93                     }
 94
 95                 }
 96             }).start();
 97         }
 98     }
 99
100 }

解释一下原因:

     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方法则是线程的安全唤醒方法。

背景知识

java中的锁池和等待池:http://blog.csdn.net/emailed/article/details/4689220

线程间协作:wait、notify、notifyAll:http://wiki.jikexueyuan.com/project/java-concurrency/collaboration-between-threads.html

java中的notify和notifyAll有什么区别?

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

今天正好碰到这个问题,也疑惑了好久。看了一圈知乎上的答案,感觉没说到根上。所以自己又好好Google了一下,终于找到了让自己信服的解释。

先说两个概念:锁池和等待池

  • 锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中。
  • 等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池中

Reference:java中的锁池和等待池

然后再来说notify和notifyAll的区别

  • 如果线程调用了对象的 wait()方法,那么线程便会处于该对象的等待池中,等待池中的线程不会去竞争该对象的锁
  • 当有线程调用了对象的 notifyAll()方法(唤醒所有 wait 线程)或 notify()方法(只随机唤醒一个 wait 线程),被唤醒的的线程便会进入该对象的锁池中,锁池中的线程会去竞争该对象锁。也就是说,调用了notify后只要一个线程会由等待池进入锁池,而notifyAll会将该对象等待池内的所有线程移动到锁池中,等待锁竞争
  • 优先级高的线程竞争到对象锁的概率大,假若某线程没有竞争到该对象锁,它还会留在锁池中,唯有线程再次调用 wait()方法,它才会重新回到等待池中。而竞争到对象锁的线程则继续往下执行,直到执行完了 synchronized 代码块,它会释放掉该对象锁,这时锁池中的线程会继续竞争该对象锁。

Reference:线程间协作:wait、notify、notifyAll

综上,所谓唤醒线程,另一种解释可以说是将线程由等待池移动到锁池,notifyAll调用后,会将全部线程由等待池移到锁池,然后参与锁的竞争,竞争成功则继续执行,如果不成功则留在锁池等待锁被释放后再次参与竞争。而notify只会唤醒一个线程。

有了这些理论基础,后面的notify可能会导致死锁,而notifyAll则不会的例子也就好解释了

原文地址:https://www.cnblogs.com/zhuhongchang/p/8468032.html

时间: 2024-11-12 23:06:17

notify和notifyAll有什么区别的相关文章

notify和notifyAll有什么区别?

先说两个概念:锁池和等待池 锁池:假设线程A已经拥有了某个对象(注意:不是类)的锁,而其它的线程想要调用这个对象的某个synchronized方法(或者synchronized块),由于这些线程在进入对象的synchronized方法之前必须先获得该对象的锁的拥有权,但是该对象的锁目前正被线程A拥有,所以这些线程就进入了该对象的锁池中.等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池中 在java中,每个对象都有两个池,锁(monitor

notify() 和 notifyAll() 有什么区别? wait()

先解释两个概念. 等待池:假设一个线程A调用了某个对象的wait()方法,线程A就会释放该对象的锁后,进入到了该对象的等待池,等待池中的线程不会去竞争该对象的锁. 锁池:只有获取了对象的锁,线程才能执行对象的 synchronized 代码,对象的锁每次只有一个线程可以获得,其他线程只能在锁池中等待 区别: notify() 方法随机唤醒对象的等待池中的一个线程,进入锁池:notifyAll() 唤醒对象的等待池中的所有线程,进入锁池. 编程过程中,有时需要让一个进程等待另一个进程,最常见的是父

java 线程之间通信以及notify与notifyAll区别。

jvm多个线程间的通信是通过 线程的锁.条件语句.以及wait().notify()/notifyAll组成. 下面来实现一个启用多个线程来循环的输出两个不同的语句. package com.app.thread; import javax.swing.plaf.SliderUI;/** * 看出问题来 * @author Gordon * */public class LockDemo { public static void main(String[] args) {//  System.o

Java线程中sleep()、wait()和notify()和notifyAll()、suspend和resume()、yield()、join()、interrupt()的用法和区别

从操作系统的角度讲,os会维护一个ready queue(就绪的线程队列).并且在某一时刻cpu只为ready queue中位于队列头部的线程服务. 但是当前正在被服务的线程可能觉得cpu的服务质量不够好,于是提前退出,这就是yield. 或者当前正在被服务的线程需要睡一会,醒来后继续被服务,这就是sleep. sleep方法不推荐使用,可用wait. 线程退出最好自己实现,在运行状态中一直检验一个状态,如果这个状态为真,就一直运行,如果外界更改了这个状态变量,那么线程就停止运行. sleep(

Java线程中sleep()、wait()和notify()和notifyAll()、yield()、join()等方法的用法和区别

Java线程中sleep().wait()和notify()和notifyAll().suspend和resume().yield().join().interrupt()的用法和区别 从操作系统的角度讲,os会维护一个ready queue(就绪的线程队列).并且在某一时刻cpu只为ready queue中位于队列头部的线程服务. 但是当前正在被服务的线程可能觉得cpu的服务质量不够好,于是提前退出,这就是yield. 或者当前正在被服务的线程需要睡一会,醒来后继续被服务,这就是sleep. 

Java notify()和notifyAll()同步唤醒上的区别

notify()和notifyAll()都是Object对象用于通知处在等待该对象的线程的方法 void notify(): 唤醒一个正在等待该对象的线程. void notifyAll(): 唤醒所有正在等待该对象的线程. 两者的最大区别在于: notifyAll使所有原来在该对象上等待被notify的线程统统退出wait的状态,变成等待该对象上的锁,一旦该对象被解锁,他们就会去竞争. notify他只是选择一个wait状态线程进行通知,并使它获得该对象上的锁,但不惊动其他同样在等待被该对象n

再谈notify和notifyAll的区别和相同

经常在往上逛,关于在java中notify和notifyAll,经常有人有以下的说法: 1 notify只会通知一个在等待的对象,而notifyAll会通知所有在等待的对象,并且所有对象都会继续运行 并且,好像都有例子可以证明.上面的说法,可以说对,也可以说不对.究其原因,在于其中有一点很关键,官方的说法如下所示: 1 2 3 4 5 6 7 8 wait,notify,notifyAll: 此方法只应由作为此对象监视器的所有者的线程来调用.通过以下三种方法之一,线程可以成为此对象监视器的所有者

Notify和NotifyAll的区别?

Notify和NotifyAll都是用来对对象进行状态改变的方式,只是他们的作用域不太一样,从字面上就能看的出来,当对象被上锁之后,当其他的方法要去访问该对象中的数据,就需要该对象对其进行解锁,当然,由于多线程一个时刻可能有很多个方法要去访问他,当采用了Notify就可以实现对指定对象对该对象数据解锁,然而其他对象依旧处于wait状态,当采用NotifyAll时,就实现了对所有对象数据的解锁的作用,所有对象开始竞争资源了.

java之sleep(),join(),yield(),wait(),notify()、notifyAll()区别

1.sleep() 使当前线程(即调用该方法的线程)暂停执行一段时间,让其他线程有机会继续执行,但它并不释放对象锁.也就是说如果有synchronized同步快,其他线程仍然不能访问共享数据.注意该方法要捕捉异常. 例 如有两个线程同时执行(没有synchronized)一个线程优先级为MAX_PRIORITY,另一个为MIN_PRIORITY,如果没有 Sleep()方法,只有高优先级的线程执行完毕后,低优先级的线程才能够执行:但是高优先级的线程sleep(500)后,低优先级就有机会执行了.