歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

Java多線程之wait()和notify()

直接看測試代碼吧,細節之處,詳見注釋

  1. package com.jadyer.thread.wait; 
  2.  
  3. /** 
  4.  * Java多線程之wait()和notify()的妙用 
  5.  * @see ================================================================================================================= 
  6.  * @see 問題:同時啟動兩個線程和同時啟動四個線程,控制台打印結果是不同的 
  7.  * @see      同時啟動兩個線程時,控制台會很規律的輸出1010101010101010 
  8.  * @see      同時啟動四個線程時,控制台起初會規律的輸出10101010,一旦某一刻輸出一個負數,那麼後面的輸出就會"一錯再錯" 
  9.  * @see 分析:對線程而言,任何一種情況,都是合理的 
  10.  * @see      這裡假設其中的一種情況:tt22先執行,此時number=0,所以執行到了decrease()方法中的wait()方法,於是tt22被阻塞 
  11.  * @see      接著tt44執行了,此時number=0,所以也執行到了decrease()方法中的wait()方法,於是tt44也被阻塞了 
  12.  * @see      然後tt11執行了,此時number=0,www.linuxidc.com於是便執行到了increase()方法中的number++和notify()方法 
  13.  * @see      重點在於tt11執行到notify()方法時,我們假設該方法喚醒了tt44線程,於是tt44開始執行decrease()方法中的number-- 
  14.  * @see      此時number=-1,然後執行到了decrease()方法中notify()方法,我們同樣假設該notify()方法喚醒的是tt22線程 
  15.  * @see      同樣的道理,number又被減減了,於是number=-2,並被打印到控制台了,然後再假設tt22中的notify()方法喚醒的是tt11 
  16.  * @see      如此的循環往復,就看到那種"一錯再錯"的效果了 
  17.  * @see ================================================================================================================= 
  18.  * @see 修復:我們應當在wait()被喚醒的時候,再判斷一次,然後再決定是否讓該線程繼續wait()下去 
  19.  * @see      因為,當某個線程被喚醒時,它不知道外界在其睡眠的期間發生了神馬,所以要再判斷一次。所以把if()改為while()判斷,即可 
  20.  * @see ================================================================================================================= 
  21.  * @see 補充:如果只有兩個線程的話,一個是對number增加的線程,一個是對number減少的線程,此時用if()判斷是沒有問題的 
  22.  * @see      因為無論線程如何的喚醒,它所喚醒的都是另一個線程,不存在第三個線程插進來搗亂的情況 
  23.  * @see ================================================================================================================= 
  24.  * @author 宏宇 
  25.  * @create Feb 22, 2012 3:20:05 PM 
  26.  */ 
  27. public class WaitNotifyTest { 
  28.     public static void main(String[] args) { 
  29.         Count count = new Count(); 
  30.          
  31.         Thread tt11 = new Thread(new IncreaseThread(count)); 
  32.         Thread tt22 = new Thread(new DecreaseThread(count)); 
  33.          
  34.         Thread tt33 = new Thread(new IncreaseThread(count)); 
  35.         Thread tt44 = new Thread(new DecreaseThread(count)); 
  36.          
  37.         tt11.start(); 
  38.         tt22.start(); 
  39.          
  40.         tt33.start(); 
  41.         tt44.start(); 
  42.     } 
  43.  
  44.  
  45. class IncreaseThread implements Runnable{ 
  46.     private Count count; 
  47.     public IncreaseThread(Count count){ 
  48.         this.count = count; 
  49.     } 
  50.     @Override 
  51.     public void run() { 
  52.         for(int i=0; i<20; i++){ 
  53.             try { 
  54.                 Thread.sleep((long)(Math.random()*1000)); 
  55.             } catch (InterruptedException e) { 
  56.                 e.printStackTrace(); 
  57.             } 
  58.             count.increase(); 
  59.         } 
  60.     } 
  61.  
  62.  
  63. class DecreaseThread implements Runnable{ 
  64.     private Count count; 
  65.     public DecreaseThread(Count count){ 
  66.         this.count = count; 
  67.     } 
  68.     @Override 
  69.     public void run() { 
  70.         for(int i=0; i<20; i++){ 
  71.             try { 
  72.                 Thread.sleep((long)(Math.random()*1000)); 
  73.             } catch (InterruptedException e) { 
  74.                 e.printStackTrace(); 
  75.             } 
  76.             count.decrease(); 
  77.         } 
  78.     } 
  79.  
  80.  
  81. class Count{ 
  82.     private int number; 
  83.      
  84.     public synchronized void increase(){ 
  85.         if(0 != number){ 
  86.             try { 
  87.                 //在同步方法(或者同步語句塊)中,被鎖定的對象可以調用wait()方法,這將導致當前線程被阻塞並釋放該對象的互斥鎖  
  88.                 //即解除了wait()方法所對應的當前對象的鎖定狀態,然後,其它的線程就有機會訪問該對象了  
  89.                 wait(); 
  90.             } catch (InterruptedException e) { 
  91.                 e.printStackTrace(); 
  92.             } 
  93.         } 
  94.         number++; 
  95.         System.out.println(number); 
  96.         //喚醒其它的由於調用了wait()方法而在等待同一個對象的線程  
  97.         //該方法每次運行時,只能喚醒等待隊列中的一個線程,至於是哪一個線程被喚醒,則由線程調度器來決定,程序員無法控制  
  98.         notify(); 
  99.     } 
  100.      
  101.     public synchronized void decrease(){ 
  102.         if(0 == number){ 
  103.             try { 
  104.                 wait(); 
  105.             } catch (InterruptedException e) { 
  106.                 e.printStackTrace(); 
  107.             } 
  108.         } 
  109.         number--; 
  110.         System.out.println(number); 
  111.         notify(); 
  112.     } 
Copyright © Linux教程網 All Rights Reserved