Java中生產(chǎn)者與消費者模式

java生產(chǎn)者與消費者模式

生產(chǎn)者和消費者模式是我們在學習多線程中很經(jīng)典的一個模式欠动,它主要分為生產(chǎn)者和消費者,分別是兩個線程.

一:生產(chǎn)者和消費者模式簡介

二:生產(chǎn)者和消費者模式的實現(xiàn)

一個自助餐里有一個做飯的廚師和來吃飯的人在扰,消費者消費食物,這里就可以把廚師當做生產(chǎn)者强窖,(吃飯的人當做消費者)碰逸,而食物則有這樣的過程,被廚師生產(chǎn)出來,然后被來吃飯的人消費奢啥。當食物存在的時候秸仙,廚師等待,不再進行生產(chǎn)桩盲,來吃飯的人進行消費寂纪。當食物為空的時候,廚師開始生產(chǎn)食物赌结,來吃飯的人等待捞蛋。這中間就存在著一個線程之間協(xié)作的過程。

0190821214620.png

首先是新建兩個線程柬姚,一個廚師線程襟交,一個服務員線程,雙方進行協(xié)作:

文中代碼github地址

以下是廚師線程:

package com.heng.subhey.consumer;

import java.util.concurrent.TimeUnit;

public class Chef  implements  Runnable{ //product

    private  Restaurant restaurant;

    private  int count=0;

    public Chef(Restaurant restaurant) {
        this.restaurant = restaurant;
    }

    @Override
    public void run() {

        try {
            while (!Thread.interrupted()) {

                synchronized (this) {

                    while (restaurant.meal != null) {

                        wait();
                    }
                    if (++count==10){

                        System.out.println("out of food,closing");
                        restaurant.exec.shutdownNow();
                    }
                    System.out.println("Chef product meal"+count);
                    synchronized (restaurant.consumerPerson){
                        restaurant.meal= new Meal(count);
                        restaurant.consumerPerson.notifyAll();
                    }
                    TimeUnit.MICROSECONDS.sleep(100);
                }

            }

        }catch (InterruptedException e){
            System.out.println("Chef interruped");

        }

    }
}

以下是消費者線程:

package com.heng.subhey.consumer;

public class ConsumerPerson implements  Runnable{

    private  Restaurant restaurant;

    public ConsumerPerson(Restaurant restaurant) {
        this.restaurant = restaurant;
    }


    @Override
    public void run() {

        try{
            while (!Thread.interrupted()) {
                synchronized (this) {
                    while (restaurant.meal == null) {
                        wait();
                    }
                    System.out.println("consumerPerson got:"+restaurant.meal);
                }
                synchronized (restaurant.chef){
                    restaurant.meal=null;
                    restaurant.chef.notifyAll();
                }
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("consumerPerson interrupdate");
        }

    }
}

我們來分析一下廚師線程伤靠,主要看它的run方法,里面包含著一個try啼染、catch塊宴合,首先它會一直捕獲線程的狀態(tài),當它不處于interrupted(線程中斷迹鹅,此時無法運轉(zhuǎn))異常時卦洽,往下走。然后取得當前對象的鎖斜棚,把它上鎖阀蒂,通過一個while循環(huán),取得餐館里面的meal弟蚀,判斷其是否為null.當餐館里面的餐還有剩余的時候蚤霞,此時生產(chǎn)者不需要工作,它處于wait狀態(tài)义钉,注意wait和Thread.sleep的區(qū)別昧绣,sleep方法運行的時候線程是不會丟棄鎖的,而wait方法會釋放鎖捶闸,所以此時夜畴,被鎖住的對象運行到wait方法,它已經(jīng)釋放了鎖删壮,因此消費者可以獲取到鎖贪绘。

再接著count會進行累加1。再接著鎖住服務員線程央碟,此時服務員線程獲取鎖的主動權(quán)税灌,它通過notifyAll方法喚醒所有的在鎖上等待線程,注意此處為什么是notifyAll而不是notify,這主要是因為此刻廚師線程并不知道等待的線程究竟是幾條垄琐,為了線程安全起見边酒,喚醒所有的等待線程。注意的是:notifyAll會喚醒所有線程狸窘,但是運行的只是其中一個墩朦,關(guān)于這個線程的篩選,是完全隨機的翻擒。

喚醒了消費者線程氓涣,它就會運行到消費者線程,然后我們來看一下它的run方法陋气,和之前的廚師線程差不多劳吠,依然是鎖住當前的消費者線程,不過線程此時的條件變成了meal為null巩趁。接著再獲取廚師的鎖痒玩,使其meal為null,再喚醒廚師線程议慰,接著程序就會運轉(zhuǎn)到廚師線程蠢古,執(zhí)行廚師的run方法。

package com.heng.subhey.consumer;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class Restaurant{

    Meal meal;

    ExecutorService exec = Executors.newCachedThreadPool();

    ConsumerPerson consumerPerson =new ConsumerPerson(this);

    Chef chef=new Chef(this);

    public Restaurant(){

        exec.execute(chef);

        exec.execute(consumerPerson);

    }

    public static void main(String[] args){

        new Restaurant();

    }
}

可以看到結(jié)果别凹,線程有條不紊的運行草讶,生產(chǎn)者每生產(chǎn)一個meal,發(fā)出order up信號,然后消費者消費這個meal炉菲,再輪到生產(chǎn)者堕战,再到消費者,這就是生產(chǎn)者和消費者的模式的意義拍霜,它們之間同步工作嘱丢,不會出現(xiàn)消費者線程沒有meal的時候仍然去消費,生產(chǎn)者在有meal的時候依然去生產(chǎn)祠饺,這樣就會產(chǎn)生線程安全的問題屿讽。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市吠裆,隨后出現(xiàn)的幾起案子伐谈,更是在濱河造成了極大的恐慌,老刑警劉巖试疙,帶你破解...
    沈念sama閱讀 222,252評論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件诵棵,死亡現(xiàn)場離奇詭異,居然都是意外死亡祝旷,警方通過查閱死者的電腦和手機履澳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評論 3 399
  • 文/潘曉璐 我一進店門嘶窄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人距贷,你說我怎么就攤上這事柄冲。” “怎么了忠蝗?”我有些...
    開封第一講書人閱讀 168,814評論 0 361
  • 文/不壞的土叔 我叫張陵现横,是天一觀的道長。 經(jīng)常有香客問我阁最,道長戒祠,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,869評論 1 299
  • 正文 為了忘掉前任速种,我火速辦了婚禮姜盈,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘配阵。我一直安慰自己馏颂,他們只是感情好,可當我...
    茶點故事閱讀 68,888評論 6 398
  • 文/花漫 我一把揭開白布棋傍。 她就那樣靜靜地躺著救拉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪舍沙。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,475評論 1 312
  • 那天剔宪,我揣著相機與錄音拂铡,去河邊找鬼。 笑死葱绒,一個胖子當著我的面吹牛感帅,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播地淀,決...
    沈念sama閱讀 41,010評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼失球,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了帮毁?” 一聲冷哼從身側(cè)響起实苞,我...
    開封第一講書人閱讀 39,924評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎烈疚,沒想到半個月后黔牵,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡爷肝,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,552評論 3 342
  • 正文 我和宋清朗相戀三年猾浦,在試婚紗的時候發(fā)現(xiàn)自己被綠了陆错。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,680評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡金赦,死狀恐怖音瓷,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情夹抗,我是刑警寧澤绳慎,帶...
    沈念sama閱讀 36,362評論 5 351
  • 正文 年R本政府宣布,位于F島的核電站兔朦,受9級特大地震影響偷线,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜沽甥,卻給世界環(huán)境...
    茶點故事閱讀 42,037評論 3 335
  • 文/蒙蒙 一声邦、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧摆舟,春花似錦亥曹、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,519評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至照宝,卻和暖如春蛇受,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背厕鹃。 一陣腳步聲響...
    開封第一講書人閱讀 33,621評論 1 274
  • 我被黑心中介騙來泰國打工兢仰, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人剂碴。 一個月前我還...
    沈念sama閱讀 49,099評論 3 378
  • 正文 我出身青樓把将,卻偏偏與公主長得像,于是被迫代替她去往敵國和親忆矛。 傳聞我的和親對象是個殘疾皇子察蹲,可洞房花燭夜當晚...
    茶點故事閱讀 45,691評論 2 361

推薦閱讀更多精彩內(nèi)容