關於Java多執行緒實現生產者和消費者的問題

java妞妞發表於2016-05-18
在學習Java多執行緒併發程式設計的同時,自己寫了一個用wait()和notifyAll()實現的生產者消費者相互阻塞,保持同步的程式。 
設定產品緩衝區上限為8,可生產者檢查counter計數器等於8的時候wait()並沒有讓多個生產者執行緒阻塞,而是繼續向下執行,對此表示不解,還請諸位高手們給菜鳥弟弟我一個解答,感激不盡!
 

Java程式碼 
  1. /*  
  2. *   這是一個與多執行緒有關的以生產者消費者問題為原型的Java程式原始碼。  
  3. *   為了體驗notify和notifyAll方法,我嘗試開啟十個生產者和五個消費者執行緒,對大小為8的緩衝區進行操作,要做到緩衝區產品達到8的時候,生產者執行緒阻塞,直到消費者執行緒減少緩衝區的產品數量,並對阻塞程式進行喚醒。  
  4. *   可現在的問題是,當生產者向緩衝區放入8個產品後,wait()方法並沒有使生產者執行緒們停住,對此表示很疑惑。  
  5.  
  6. */  
  7.   
  8.   
  9.   
  10. import java.util.concurrent.ExecutorService;   
  11. import java.util.concurrent.Executors;   
  12.   
  13. class myProducer implements Runnable   
  14. {   
  15.     private myProAndCon mpc;   
  16.        
  17.     myProducer( myProAndCon mpac ){ this.mpc =  mpac; }   
  18.        
  19.     public void run()   
  20.     {   
  21.         try {   
  22.             while(!Thread.interrupted())   
  23.             {      
  24.                     //生產者互斥   
  25.                     synchronized (this){   
  26.   
  27.                         //靜態計數值達到上限,則wait()阻塞,等待被消費者執行緒喚醒   
  28.                         while ( mpc.get() >= 8 )   
  29.                            
  30.                         {   
  31.                        
  32.                             System.out.println(mpc.get());   
  33.                                 wait();   
  34.                         }   
  35.                     }   
  36.                        
  37.                     Thread.sleep(100);   
  38.                        
  39.                     //未發生阻塞時,向緩衝區內放入產品,增加計數值,並喚醒所有阻塞的消費者執行緒   
  40.                     synchronized ( mpc.c ){   
  41.                             System.out.println("[ P ] The number is " + mpc.inc() );   
  42.                             mpc.c.notifyAll();   
  43.                     }   
  44.             }   
  45.         } catch (InterruptedException e) {   
  46.             // TODO Auto-generated catch block   
  47.             e.printStackTrace();   
  48.         }   
  49.     }   
  50. }   
  51.   
  52.   
  53. class myConsumer implements Runnable   
  54. {   
  55.     private myProAndCon mpc;   
  56.        
  57.     myConsumer( myProAndCon mpac ){ this.mpc =  mpac; }   
  58.        
  59.     public void run()   
  60.     {      
  61.         try {   
  62.             while(!Thread.interrupted())   
  63.             {   
  64.                 //消費者互斥   
  65.                 synchronized ( this )   
  66.                 {   
  67.                     //當緩衝區無產品時,消費者執行緒阻塞,等待被生產者執行緒喚醒   
  68.                     while ( mpc.get() <= 0 )   
  69.                         wait();   
  70.                 }   
  71.                    
  72.                 Thread.sleep(3000);   
  73.                    
  74.                 //未發生阻塞時,從緩衝區取出產品,減少計數值,並喚醒所有阻塞的生產者執行緒   
  75.                 synchronized (mpc.p){   
  76.                         System.out.println("[ C ] The number is " + mpc.dec() );   
  77.                         mpc.p.notifyAll();   
  78.                 }   
  79.                        
  80.                    
  81.             }   
  82.         } catch (InterruptedException e) {   
  83.             // TODO Auto-generated catch block   
  84.             e.printStackTrace();   
  85.         }   
  86.            
  87.     }   
  88. }   
  89.   
  90.   
  91.   
  92.   
  93. public class myProAndCon {   
  94.     //public final int S = 8;   
  95.   
  96.     //緩衝區計數器(靜態)以及對其進行的三個synchronized操作   
  97.     volatile private static int  counter = 0;   
  98.        
  99.     synchronized static int inc(){ return ++ counter; }   
  100.     synchronized static int dec(){ return  counter -= 2; }   
  101.     synchronized static int get(){ return  counter; }   
  102.   
  103.     //構造兩個物件,作為開啟執行緒的引數   
  104.     public myConsumer c = new myConsumer(this);   
  105.     public myProducer p = new myProducer(this);   
  106.        
  107.     private ExecutorService exec = Executors.newCachedThreadPool();   
  108.        
  109.     public myProAndCon(){   
  110.            
  111.         //開啟十個生產者執行緒   
  112.         for ( int i  = 0 ; i < 10 ; i ++ )   
  113.             exec.execute(p);   
  114.            
  115.         //開啟五個消費者執行緒   
  116.         for  ( int i = 0 ; i < 5 ; i ++ )   
  117.             exec.execute(c);   
  118.            
  119.     }   
  120.        
  121.   
  122.     //主函式呼叫myProAndCon類構造方法,開始執行各個執行緒   
  123.     public static void main(String[] s)   
  124.     {   
  125.         new myProAndCon();   
  126.     }   
  127.        
  128.        
在學習中有困難需要交流不知道怎麼去做的可以關注微信公眾號:javaniuniu得到大神指導和幫助,獲取免費的聽課許可權。

相關文章