java鎖之wait,notify(wait會釋放鎖,notify僅僅只是通知,不釋放鎖)


wait是指在一個已經進入了同步鎖的線程內,讓自己暫時讓出同步鎖,以便其他正在等待此鎖的線程可以得到同步鎖並運行,只有其他線程調用了notify方法(notify並不釋放鎖,只是告訴調用過wait方法的線程可以去參與獲得鎖的競爭了,但不是馬上得到鎖,因為鎖還在別人手里,別人還沒釋放),調用wait方法的一個或多個線程就會解除wait狀態,重新參與競爭對象鎖,程序如果可以再次得到鎖,就可以繼續向下運行。

 

  1)wait()、notify()和notifyAll()方法是本地方法,並且為final方法,無法被重寫。

 

 2)當前線程必須擁有此對象的monitor(即鎖),才能調用某個對象的wait()方法能讓當前線程阻塞,

    (這種阻塞是通過提前釋放synchronized鎖,重新去請求鎖導致的阻塞,這種請求必須有其他線程通過notify()或者notifyAll()喚醒重新競爭獲得鎖)

 

 3)調用某個對象的notify()方法能夠喚醒一個正在等待這個對象的monitor的線程,如果有多個線程都在等待這個對象的monitor,則只能喚醒其中一個線程;

 (notify()或者notifyAll()方法並不是真正釋放鎖,必須等到synchronized方法或者語法塊執行完才真正釋放鎖)

 

 4)調用notifyAll()方法能夠喚醒所有正在等待這個對象的monitor的線程,喚醒的線程獲得鎖的概率是隨機的,取決於cpu調度

 

  例子1(錯誤使用導致線程阻塞):三個線程,線程3先擁有sum對象的鎖,然后通過sum.notify()方法通知等待sum鎖的線程去獲得鎖,但是這個時候線程1,2並沒有處於wait()導致的阻塞狀態,而是在synchronized方法塊處阻塞了,所以,這次notify()根本沒有通知到線程1,2。然后線程3正常結束,釋放掉sum鎖,這個時候,線程1就立刻獲得了sum對象的鎖(通過synchronized獲得),然后調用sum.wait()方法釋放掉sum的鎖,線程2隨后獲得了sum對象的線程鎖(通過synchronized獲得),這個時候線程1,2都處於阻塞狀態,但是悲催的是,這之后再也沒有線程主動調用sum.notify()或者notifyAll()方法顯示喚醒這兩個線程,所以程序阻塞

Java代碼  收藏代碼
  1. public class CyclicBarrierTest {  
  2.       
  3.     public static void main(String[] args) throws Exception {  
  4.         final Sum sum=new Sum();  
  5.           
  6.         new Thread(new Runnable() {  
  7.             @Override  
  8.             public void  run() {  
  9.                 try {  
  10.                     synchronized (sum) {  
  11.                         System.out.println("thread3 get lock");  
  12.                         sum.sum();  
  13.                         sum.notifyAll(); //此時喚醒沒有作用,沒有線程等待  
  14.                         Thread.sleep(2000);  
  15.                         System.out.println("thread3 really release lock");  
  16.                     }  
  17.                       
  18.                 } catch (Exception e) {  
  19.                     e.printStackTrace();  
  20.                 }  
  21.             }  
  22.         }).start();  
  23.           
  24.         new Thread(new Runnable() {  
  25.             @Override  
  26.             public void  run() {  
  27.                 try {  
  28.                     synchronized (sum) {  
  29.                         System.out.println("thread1 get lock");  
  30.                         sum.wait();//主動釋放掉sum對象鎖  
  31.                         System.out.println(sum.total);  
  32.                         System.out.println("thread1 release lock");  
  33.                     }  
  34.                 } catch (Exception e) {  
  35.                     e.printStackTrace();  
  36.                 }  
  37.             }  
  38.         }).start();  
  39.           
  40.         new Thread(new Runnable() {  
  41.             @Override  
  42.             public void  run() {  
  43.                 try {  
  44.                     synchronized (sum) {  
  45.                         System.out.println("thread2 get lock");  
  46.                         sum.wait();  //釋放sum的對象鎖,等待其他對象喚醒(其他對象釋放sum鎖)  
  47.                         System.out.println(sum.total);  
  48.                         System.out.println("thread2 release lock");  
  49.                     }  
  50.                 } catch (Exception e) {  
  51.                     e.printStackTrace();  
  52.                 }  
  53.             }  
  54.         }).start();  
  55.     }  
  56.             
  57. }  
  58.   
  59. class Sum{  
  60.     public Integer total=0;  
  61.       
  62.     public void  sum() throws Exception{  
  63.         total=100;  
  64.         Thread.sleep(5000);  
  65.     }  
  66.       
  67. }  

 

 

    運行結果:

 

Java代碼  收藏代碼
  1. thread3 get lock  
  2. thread3 really release lock  
  3. thread2 get lock  
  4. thread1 get lock  
  5. //程序后面一直阻塞  

 例子2:還是上面程序,順序不同,把線程3放到最下面。最后線程1,2都因為沒有再次獲得線程導致線程阻塞

 

運行過程:

線程1先運行獲得sum對象鎖(通過synchronized),但是隨后執行了sum.wait()方法,主動釋放掉了sum對象鎖,然后線程2獲得了sum對象鎖(通過synchronized),也通過sum.wait()失去sum的對象鎖,最后線程3獲得了sum對象鎖(通過synchronized),主動通過sum.notify()通知了線程1或者2,假設是1,線程1重新通過notify()/notifyAll()的方式獲得了鎖,然后執行完畢,隨后線程釋放鎖,然后這個時候線程2成功獲得鎖,執行完畢。

Java代碼  收藏代碼
  1. public class CyclicBarrierTest {  
  2.       
  3.     public static void main(String[] args) throws Exception {  
  4.         final Sum sum=new Sum();  
  5.           
  6.       
  7.           
  8.         new Thread(new Runnable() {  
  9.             @Override  
  10.             public void  run() {  
  11.                 try {  
  12.                     synchronized (sum) {  
  13.                         System.out.println("thread1 get lock");  
  14.                         sum.wait();//主動釋放sum對象鎖,等待喚醒  
  15.                         System.out.println(sum.total);  
  16.                         System.out.println("thread1 release lock");  
  17.                     }  
  18.                 } catch (Exception e) {  
  19.                     e.printStackTrace();  
  20.                 }  
  21.             }  
  22.         }).start();  
  23.           
  24.         new Thread(new Runnable() {  
  25.             @Override  
  26.             public void  run() {  
  27.                 try {  
  28.                     synchronized (sum) {  
  29.                         System.out.println("thread2 get lock");  
  30.                         sum.wait();  //主動釋放sum對象鎖,等待喚醒  
  31.                         System.out.println(sum.total);  
  32.                         System.out.println("thread2 release lock");  
  33.                     }  
  34.                 } catch (Exception e) {  
  35.                     e.printStackTrace();  
  36.                 }  
  37.             }  
  38.         }).start();  
  39.           
  40.         new Thread(new Runnable() {  
  41.             @Override  
  42.             public void  run() {  
  43.                 try {  
  44.                     synchronized (sum) {  
  45.                         System.out.println("thread3 get lock");  
  46.                         sum.sum();  
  47.                         sum.notifyAll();//喚醒其他等待線程(線程1,2)  
  48.                         Thread.sleep(2000);  
  49.                         System.out.println("thread3 really release lock");  
  50.                     }  
  51.                       
  52.                 } catch (Exception e) {  
  53.                     e.printStackTrace();  
  54.                 }  
  55.             }  
  56.         }).start();  
  57.           
  58.           
  59.     }  
  60.             
  61. }  
  62.   
  63. class Sum{  
  64.     public Integer total=0;  
  65.       
  66.     public void  sum() throws Exception{  
  67.         total=100;  
  68.         Thread.sleep(5000);  
  69.     }  
  70.       
  71. }  

 

執行結果:

Java代碼  收藏代碼
    1. thread1 get lock  
    2. thread2 get lock  
    3. thread3 get lock  
    4. thread3 really release lock  
    5. 100  
    6. thread2 release lock  
    7. 100  
    8. thread1 release lock 

轉自 https://blog.csdn.net/azhegps/article/details/63031562


免責聲明!

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



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