轉: 【Java並發編程】之十三:生產者—消費者模型(含代碼)
阿新 • • 發佈:2017-05-30
tool boolean 通知 阻塞 上一個 [] ble 否則 線程
轉載請註明出處:http://blog.csdn.net/ns_code/article/details/17249321
生產者消費者問題是線程模型中的經典問題:生產者和消費者在同一時間段內共用同一存儲空間,生產者向空間裏生產數據,而消費者取走數據。
這裏實現如下情況的生產--消費模型:
生產者不斷交替地生產兩組數據“姓名--1 --> 內容--1”,“姓名--2--> 內容--2”,消費者不斷交替地取得這兩組數據,這裏的“姓名--1”和“姓名--2”模擬為數據的名稱,“內容--1 ”和“內容--2 ”模擬為數據的內容。
由於本程序中牽扯到線程運行的不確定性,因此可能會出現以下問題:
1、假設生產者線程剛向數據存儲空間添加了數據的名稱,還沒有加入該信息的內容,程序就切換到了消費者線程,消費者線程將把信息的名稱和上一個信息的內容聯系在一起;
2、生產者生產了若幹次數據,消費者才開始取數據,或者是,消費者取完一次數據後,還沒等生產者放入新的數據,又重復取出了已取過的數據。
問題1很明顯要靠同步來解決,問題2則需要線程間通信,生產者線程放入數據後,通知消費者線程取出數據,消費者線程取出數據後,通知生產者線程生產數據,這裏用wait/notify機制來實現。
詳細的實現代碼如下:
[java] view plain copy- class Info{ // 定義信息類
- private String name = "name";//定義name屬性,為了與下面set的name屬性區別開
- private String content = "content" ;// 定義content屬性,為了與下面set的content屬性區別開
- private boolean flag = true ; // 設置標誌位,初始時先生產
- public synchronized void set(String name,String content){
- while(!flag){
- try{
- super.wait() ;
- }catch(InterruptedException e){
- e.printStackTrace() ;
- }
- }
- this.setName(name) ; // 設置名稱
- try{
- Thread.sleep(300) ;
- }catch(InterruptedException e){
- e.printStackTrace() ;
- }
- this.setContent(content) ; // 設置內容
- flag = false ; // 改變標誌位,表示可以取走
- super.notify();
- }
- public synchronized void get(){
- while(flag){
- try{
- super.wait() ;
- }catch(InterruptedException e){
- e.printStackTrace() ;
- }
- }
- try{
- Thread.sleep(300) ;
- }catch(InterruptedException e){
- e.printStackTrace() ;
- }
- System.out.println(this.getName() +
- " --> " + this.getContent()) ;
- flag = true ; // 改變標誌位,表示可以生產
- super.notify();
- }
- public void setName(String name){
- this.name = name ;
- }
- public void setContent(String content){
- this.content = content ;
- }
- public String getName(){
- return this.name ;
- }
- public String getContent(){
- return this.content ;
- }
- }
- class Producer implements Runnable{ // 通過Runnable實現多線程
- private Info info = null ; // 保存Info引用
- public Producer(Info info){
- this.info = info ;
- }
- public void run(){
- boolean flag = true ; // 定義標記位
- for(int i=0;i<10;i++){
- if(flag){
- this.info.set("姓名--1","內容--1") ; // 設置名稱
- flag = false ;
- }else{
- this.info.set("姓名--2","內容--2") ; // 設置名稱
- flag = true ;
- }
- }
- }
- }
- class Consumer implements Runnable{
- private Info info = null ;
- public Consumer(Info info){
- this.info = info ;
- }
- public void run(){
- for(int i=0;i<10;i++){
- this.info.get() ;
- }
- }
- }
- public class ThreadCaseDemo03{
- public static void main(String args[]){
- Info info = new Info(); // 實例化Info對象
- Producer pro = new Producer(info) ; // 生產者
- Consumer con = new Consumer(info) ; // 消費者
- new Thread(pro).start() ;
- //啟動了生產者線程後,再啟動消費者線程
- try{
- Thread.sleep(500) ;
- }catch(InterruptedException e){
- e.printStackTrace() ;
- }
- new Thread(con).start() ;
- }
- }
執行結果如下:
另外,在run方法中,二者循環的次數要相同,否則,當一方的循環結束時,另一方的循環依然繼續,它會阻塞在wait()方法處,而等不到對方的notify通知。
轉: 【Java並發編程】之十三:生產者—消費者模型(含代碼)