天天看點

線程(三)線程協作生産者與消費者

線程互斥就是我們前面所學到的臨界區的加鎖機制就是使用synchronized和關鍵字volatile進行同步操作,但是線程之間僅僅通過互斥還不能很号的工作我們還需要線程之間的協作,就是我們今天所要探究的生産者和消費者.

生産者和消費者模型相信大家在大學的作業系統一門課中已經有所接觸;具體的意思就是有一個公共的區域我們作為商品池,生産着呢就往這個池子放生産出來的商品,當這個池子滿的時候生産者就不能在往裡面放東西了,那麼他現在有倆個選擇,一個就是進入阻塞隊列中,等待消費者消費池子中的商品,池子中的商品被消費之後他才可以進行商品的繼續 放進去,還有一個就是他在池子滿的時候丢棄生産出來的商品.那麼 相對應的就是消費者了,消費者呢在池子中有商品的時候可以取池子中的商品 進行消費,當池子中沒有商品的時候他就隻有一手準備了就是,等待池子中有商品 了在進行商品的消費.

現在我們通過一個例子來說明下生産者和消費者:比如有一個籃子,他裡面存放雞蛋,當有雞蛋的時候呢生産者等待或者丢棄,知道消費者把雞蛋拿走,他才能在籃子裡放新的雞蛋,消費者呢就是當籃子裡有雞蛋的時候才去取籃子中的雞蛋直到籃子沒有雞蛋了就等待,當生産者重新放入雞蛋在籃子裡他就取雞蛋消費.好了我們看看我們的代碼實作

首先是存放的雞蛋類:      
/**
 * Created by luyangli on 16-6-21.
 */
public class Egg {
    private String egg;

    public String getEgg() {
        return egg;
    }

    public void setEgg(String egg) {
        this.egg = egg;
    }

    public Egg(String egg) {
        this.egg = egg;
    }
}      
可以看到什麼都沒有做,隻是一個成員變量,其實這個變量我們也可以不用設定,就鍵一個空的類就可以
然後呢就是我們的籃子:
       
/**
 * Created by luyangli on 16-6-21.
 */
public class Plate {
    public static void main(String[] args) {
        List<Egg> eggList = new ArrayList<Egg>();   //注意這個就是籃子啦
        Provider provider = new Provider(eggList);  //生産者
        Consumer consumer = new Consumer(eggList);  //消費者
        for (int i=0; i<10; i++) {        //分别啟動10個線程
            new Thread(provider).start();
            new Thread(consumer).start();
        }
    }
}
      
這個就是我們的籃子,其實我們的籃子就是一個清單,其實按照我們所說的,隻要一個長度的清單就OK啦,當有雞蛋的時候生産者等待,就是說有一個雞蛋的收生産者也是等待狀态,消費者消費,當沒有雞蛋的時候消費者等待.在這裡我們需要構造一個消費者和一個生産者執行個體,我們可以看到消費者和生産者是使用同一個籃子,這樣的話就不會放在别的籃子裡來了.
然後就是我們的消費者和生産者:      
/**
 * Created by luyangli on 16-6-21.
 */
public class Provider implements Runnable {

    private List<Egg> eggList;

    public Provider(List<Egg> eggList) {
        this.eggList = eggList;
    }

    private synchronized void putEgg(){
        while (eggList.size() > 0){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Egg egg = new Egg("egg");
        eggList.add(egg);
        System.out.println("加入了雞蛋");
        notify();
    }

    @Override public void run() {
        putEgg();
    }
}      
生産者就是在籃子有雞蛋的時候呢,等待,當沒有雞蛋的時候就添加雞蛋,喚醒消費者消費
/**
 * Created by luyangli on 16-6-21.
 */
public class Consumer implements Runnable{

    private List<Egg> eggList;

    public Consumer(List<Egg> eggList) {
        this.eggList = eggList;
    }

    private synchronized void getEgg(){
        while (eggList.size() <= 0){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        Egg egg = eggList.get(0);
        eggList.clear();
        notify();
        System.out.println("拿到了雞蛋");
    }

    @Override public void run() {
        getEgg();
    }
}
      
消費者呢就是在籃子沒有雞蛋的時候等待,要是籃子有雞蛋的話就消費然後喚醒生産者添加雞蛋.
我們想要的結果是這樣的:當籃子有雞蛋的時候就通知消費者進行消費,這個時候生産者是等待的狀态,籃子沒有雞蛋的時候是生産者添加雞蛋,消費者是等待狀态的,我們來看你一下執行的效果是不是我們所期望的:
加入了雞蛋
拿到了雞蛋
加入了雞蛋
拿到了雞蛋
加入了雞蛋
拿到了雞蛋
加入了雞蛋
拿到了雞蛋
加入了雞蛋
拿到了雞蛋
加入了雞蛋
拿到了雞蛋
加入了雞蛋
加入了雞蛋
拿到了雞蛋
拿到了雞蛋
加入了雞蛋
拿到了雞蛋
加入了雞蛋
拿到了雞蛋
      
看起來這個結果是我們索要的,但是我們要是執行多次呢:
加入了雞蛋
拿到了雞蛋
加入了雞蛋
拿到了雞蛋
加入了雞蛋
拿到了雞蛋
加入了雞蛋
拿到了雞蛋
加入了雞蛋
拿到了雞蛋
加入了雞蛋
拿到了雞蛋
加入了雞蛋
拿到了雞蛋
加入了雞蛋
拿到了雞蛋
      
這個怎麼才有8個線程在操作一樣,其他的兩個線程呢,這個問題先記這,有沒有大神給我指點下迷津呢,ganjibujin