歡迎來到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.  
  46. class IncreaseThread implements Runnable{ 
  47.     private Count count; 
  48.     public IncreaseThread(Count count){ 
  49.         this.count = count; 
  50.     } 
  51.     @Override 
  52.     public void run() { 
  53.         for(int i=0; i<20; i++){ 
  54.             try { 
  55.                 Thread.sleep((long)(Math.random()*1000)); 
  56.             } catch (InterruptedException e) { 
  57.                 e.printStackTrace(); 
  58.             } 
  59.             count.increase(); 
  60.         } 
  61.     } 
  62. } 
  63.  
  64.  
  65. class DecreaseThread implements Runnable{ 
  66.     private Count count; 
  67.     public DecreaseThread(Count count){ 
  68.         this.count = count; 
  69.     } 
  70.     @Override 
  71.     public void run() { 
  72.         for(int i=0; i<20; i++){ 
  73.             try { 
  74.                 Thread.sleep((long)(Math.random()*1000)); 
  75.             } catch (InterruptedException e) { 
  76.                 e.printStackTrace(); 
  77.             } 
  78.             count.decrease(); 
  79.         } 
  80.     } 
  81. } 
  82.  
  83.  
  84. class Count{ 
  85.     private int number; 
  86.      
  87.     public synchronized void increase(){ 
  88.         if(0 != number){ 
  89.             try { 
  90.                 //在同步方法(或者同步語句塊)中,被鎖定的對象可以調用wait()方法,這將導致當前線程被阻塞並釋放該對象的互斥鎖  
  91.                 //即解除了wait()方法所對應的當前對象的鎖定狀態,然後,其它的線程就有機會訪問該對象了  
  92.                 wait(); 
  93.             } catch (InterruptedException e) { 
  94.                 e.printStackTrace(); 
  95.             } 
  96.         } 
  97.         number++; 
  98.         System.out.println(number); 
  99.         //喚醒其它的由於調用了wait()方法而在等待同一個對象的線程  
  100.         //該方法每次運行時,只能喚醒等待隊列中的一個線程,至於是哪一個線程被喚醒,則由線程調度器來決定,程序員無法控制  
  101.         notify(); 
  102.     } 
  103.      
  104.     public synchronized void decrease(){ 
  105.         if(0 == number){ 
  106.             try { 
  107.                 wait(); 
  108.             } catch (InterruptedException e) { 
  109.                 e.printStackTrace(); 
  110.             } 
  111.         } 
  112.         number--; 
  113.         System.out.println(number); 
  114.         notify(); 
  115.     } 
  116. } 
Copyright © Linux教程網 All Rights Reserved