【Java併發編程】之十三:生產者—消費者模型

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

​ 這裏實現以下狀況的生產--消費模型:多線程

​ 生產者不斷交替地生產兩組數據「姓名--1 --> 內容--1」,「姓名--2--> 內容--2」,消費者不斷交替地取得這兩組數據,這裏的「姓名--1」和「姓名--2」模擬爲數據的名稱,「內容--1 」和「內容--2 」模擬爲數據的內容。this

​ 因爲本程序中牽扯到線程運行的不肯定性,所以可能會出現如下問題:線程

​ 一、假設生產者線程剛向數據存儲空間添加了數據的名稱,尚未加入該信息的內容,程序就切換到了消費者線程,消費者線程將把信息的名稱和上一個信息的內容聯繫在一塊兒;code

​ 二、生產者生產了若干次數據,消費者纔開始取數據,或者是,消費者取完一次數據後,還沒等生產者放入新的數據,又重複取出了已取過的數據。對象

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

​ 詳細的實現代碼以下:get

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() ;  
    }  
}

執行結果以下:同步

img

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

相關文章
相關標籤/搜索