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則不會的例子也就好解釋了


 
 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM