生產者—消費者模型


 生產者消費者問題是線程模型中的經典問題:生產者和消費者在同一時間段內共用同一存儲空間,生產者向空間里生產數據,而消費者取走數據。

這里實現如下情況的生產--消費模型:

    生產者不斷交替地生產兩組數據“姓名--1 --> 內容--1”,“姓名--2--> 內容--2”,消費者不斷交替地取得這兩組數據,這里的“姓名--1”和“姓名--2”模擬為數據的名稱,“內容--1 ”和“內容--2 ”模擬為數據的內容。

  由於本程序中牽扯到線程運行的不確定性,因此可能會出現以下問題:

     1、假設生產者線程剛向數據存儲空間添加了數據的名稱,還沒有加入該信息的內容,程序就切換到了消費者線程,消費者線程將把信息的名稱和上一個信息的內容聯系在一起;

     2、生產者生產了若干次數據,消費者才開始取數據,或者是,消費者取完一次數據后,還沒等生產者放入新的數據,又重復取出了已取過的數據。

 

     問題1很明顯要靠同步來解決,問題2則需要線程間通信,生產者線程放入數據后,通知消費者線程取出數據,消費者線程取出數據后,通知生產者線程生產數據,這里用wait/notify機制來實現。

 詳細的實現代碼如下:

 1 class Info{ // 定義信息類  
 2     private String name = "name";//定義name屬性,為了與下面set的name屬性區別開  
 3     private String content = "content" ;// 定義content屬性,為了與下面set的content屬性區別開  
 4     private boolean flag = true ;   // 設置標志位,初始時先生產  
 5     public synchronized void set(String name,String content){  
 6         while(!flag){  
 7             try{  
 8                 super.wait() ;  
 9             }catch(InterruptedException e){  
10                 e.printStackTrace() ;  
11             }  
12         }  
13         this.setName(name) ;    // 設置名稱  
14         try{  
15             Thread.sleep(300) ;  
16         }catch(InterruptedException e){  
17             e.printStackTrace() ;  
18         }  
19         this.setContent(content) ;  // 設置內容  
20         flag  = false ; // 改變標志位,表示可以取走  
21         super.notify();  
22     }  
23     public synchronized void get(){  
24         while(flag){  
25             try{  
26                 super.wait() ;  
27             }catch(InterruptedException e){  
28                 e.printStackTrace() ;  
29             }  
30         }  
31         try{  
32             Thread.sleep(300) ;  
33         }catch(InterruptedException e){  
34             e.printStackTrace() ;  
35         }  
36         System.out.println(this.getName() +   
37             " --> " + this.getContent()) ;  
38         flag  = true ;  // 改變標志位,表示可以生產  
39         super.notify();  
40     }  
41     public void setName(String name){  
42         this.name = name ;  
43     }  
44     public void setContent(String content){  
45         this.content = content ;  
46     }  
47     public String getName(){  
48         return this.name ;  
49     }  
50     public String getContent(){  
51         return this.content ;  
52     }  
53 }  
54 class Producer implements Runnable{ // 通過Runnable實現多線程  
55     private Info info = null ;      // 保存Info引用  
56     public Producer(Info info){  
57         this.info = info ;  
58     }  
59     public void run(){  
60         boolean flag = true ;   // 定義標記位  
61         for(int i=0;i<10;i++){  
62             if(flag){  
63                 this.info.set("姓名--1","內容--1") ;    // 設置名稱  
64                 flag = false ;  
65             }else{  
66                 this.info.set("姓名--2","內容--2") ;    // 設置名稱  
67                 flag = true ;  
68             }  
69         }  
70     }  
71 }  
72 class Consumer implements Runnable{  
73     private Info info = null ;  
74     public Consumer(Info info){  
75         this.info = info ;  
76     }  
77     public void run(){  
78         for(int i=0;i<10;i++){  
79             this.info.get() ;  
80         }  
81     }  
82 }  
83 public class ThreadCaseDemo03{  
84     public static void main(String args[]){  
85         Info info = new Info(); // 實例化Info對象  
86         Producer pro = new Producer(info) ; // 生產者  
87         Consumer con = new Consumer(info) ; // 消費者  
88         new Thread(pro).start() ;  
89         //啟動了生產者線程后,再啟動消費者線程  
90         try{  
91             Thread.sleep(500) ;  
92         }catch(InterruptedException e){  
93             e.printStackTrace() ;  
94         }  
95   
96         new Thread(con).start() ;  
97     }  
98 }  

執行結果如下:

 另外,在run方法中,二者循環的次數要相同,否則,當一方的循環結束時,另一方的循環依然繼續,它會阻塞在wait()方法處,而等不到對方的notify通知


免責聲明!

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



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