wait/notify實現(xiàn)生產(chǎn)者消費(fèi)者(6)

生產(chǎn)者消費(fèi)者模型

生產(chǎn)者消費(fèi)者模型是一個典型的多線程問題悠咱,涉及生產(chǎn)者、消費(fèi)者征炼、產(chǎn)品倉庫析既。生產(chǎn)者生產(chǎn)的產(chǎn)品放入倉庫中、消費(fèi)者從倉庫中取走產(chǎn)品谆奥。倉庫可看成是阻塞隊列眼坏,有如下關(guān)系。

  • 倉庫放滿產(chǎn)品后生產(chǎn)者停止生產(chǎn)
  • 倉庫中沒有產(chǎn)品時消費(fèi)者停止消費(fèi)
  • 倉庫不滿的時候所有生產(chǎn)者都進(jìn)行工作,倉庫有產(chǎn)品后通知消費(fèi)者消費(fèi)
  • 倉庫有產(chǎn)品的時候所有消費(fèi)者都工作宰译,倉庫不滿時通知生產(chǎn)者生產(chǎn)

代碼實現(xiàn)

import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author HXJ
 * @date 2018/7/26
 */
public class ProduceConsume {
    static class Produce {
        public Produce(String name) {
            this.name = name;
        }

        private String name;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Produce{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }
    //單向鏈表檐蚜,用于構(gòu)建隊列
    static class Node {
        Produce produce;
        Node next;
        Node(Produce produce) { this.produce = produce; }
    }
    static class ProduceDepot {
        private int capacity;
        private final AtomicInteger count = new AtomicInteger();
        private Node head;
        private Node tail;
        private Object notFull = new Object();
        private Object notEmpty = new Object();

        public ProduceDepot(int capacity) {
            this.capacity = capacity;
            this.head = this.tail = new Node(null);
        }

        public void produce(Produce produce) {
            Node node = new Node(produce);
            int num;
            synchronized (notFull) {
                while (count.get() == this.capacity) {
                    try {
                        //如果倉庫滿了,停止生產(chǎn)
                        System.out.println(Thread.currentThread().getName() + " 倉庫滿了沿侈,停止生產(chǎn)");
                        notFull.wait();
                    } catch (InterruptedException e) {
                    }
                }
                //新生產(chǎn)的產(chǎn)品排隊放入倉庫闯第,放在隊列末尾
                this.tail = this.tail.next = node;
                num = count.getAndIncrement();
                if (num + 1 < this.capacity) {
                    //如果隊列不滿了通知生產(chǎn)
                    notFull.notifyAll();
                    System.out.println(Thread.currentThread().getName() + " 倉庫沒滿,通知其他生產(chǎn)者");
                }
            }
            if (num == 0) {
                synchronized (notEmpty) {
                    System.out.println(Thread.currentThread().getName() + " 倉庫有產(chǎn)品缀拭,通知消費(fèi)者消費(fèi)");
                    notEmpty.notifyAll();
                }
            }
        }

        public Produce consume() {
            int num;
            Produce produce;
            synchronized (notEmpty) {
                while (count.get() == 0) {
                    try {
                        System.out.println(Thread.currentThread().getName() + " 倉庫空了咳短,停止消費(fèi)");
                        notEmpty.wait();
                    } catch (InterruptedException e) {
                    }
                }
                //把先進(jìn)倉庫的產(chǎn)品取出
                Node h = this.head;
                Node first = this.head.next;
                this.head = first;
                h.next = null; //gc
                produce = first.produce;
                first.produce = null;

                num = count.getAndDecrement();
                if (num > 1) {
                    System.out.println(Thread.currentThread().getName() + " 倉庫有產(chǎn)品,通知其他消費(fèi)者");
                    notEmpty.notifyAll();
                }
            }
            if (num == this.capacity) {
                //隊列不滿了蛛淋,通知生產(chǎn)者
                synchronized (notFull) {
                    System.out.println(Thread.currentThread().getName() + " 倉庫不滿了咙好,通知繼續(xù)生產(chǎn)");
                    notFull.notifyAll();
                }
            }
            return produce;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        ProduceDepot depot = new ProduceDepot(10);
        new Thread(new Runnable() {
            @Override
            public void run() {
                int i = 0;
                while (true) {
                    depot.produce(new Produce("produce-" + i));
                    i ++;
                }
            }
        }, "produce").start();

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    System.out.println("消費(fèi)產(chǎn)品:" + depot.consume());
                }
            }
        }, "consume").start();
        Thread.currentThread().join();
    }
}

運(yùn)行結(jié)果:

...
消費(fèi)產(chǎn)品:Produce{name='produce-67303'}
consume 倉庫空了,停止消費(fèi)
produce 倉庫沒滿褐荷,通知其他生產(chǎn)者
produce 倉庫沒滿勾效,通知其他生產(chǎn)者
produce 倉庫有產(chǎn)品,通知消費(fèi)者消費(fèi)
produce 倉庫沒滿叛甫,通知其他生產(chǎn)者
consume 倉庫有產(chǎn)品层宫,通知其他消費(fèi)者
消費(fèi)產(chǎn)品:Produce{name='produce-67304'}
consume 倉庫有產(chǎn)品,通知其他消費(fèi)者
消費(fèi)產(chǎn)品:Produce{name='produce-67305'}
消費(fèi)產(chǎn)品:Produce{name='produce-67306'}
consume 倉庫空了合溺,停止消費(fèi)
produce 倉庫沒滿卒密,通知其他生產(chǎn)者
produce 倉庫沒滿缀台,通知其他生產(chǎn)者
produce 倉庫有產(chǎn)品棠赛,通知消費(fèi)者消費(fèi)
produce 倉庫沒滿,通知其他生產(chǎn)者
consume 倉庫有產(chǎn)品膛腐,通知其他消費(fèi)者
消費(fèi)產(chǎn)品:Produce{name='produce-67307'}
consume 倉庫有產(chǎn)品睛约,通知其他消費(fèi)者
消費(fèi)產(chǎn)品:Produce{name='produce-67308'}
消費(fèi)產(chǎn)品:Produce{name='produce-67309'}
consume 倉庫空了,停止消費(fèi)
produce 倉庫沒滿哲身,通知其他生產(chǎn)者
produce 倉庫沒滿辩涝,通知其他生產(chǎn)者
produce 倉庫有產(chǎn)品,通知消費(fèi)者消費(fèi)
produce 倉庫沒滿勘天,通知其他生產(chǎn)者
produce 倉庫沒滿怔揩,通知其他生產(chǎn)者
produce 倉庫沒滿,通知其他生產(chǎn)者
produce 倉庫沒滿脯丝,通知其他生產(chǎn)者
produce 倉庫沒滿商膊,通知其他生產(chǎn)者
produce 倉庫沒滿,通知其他生產(chǎn)者
produce 倉庫沒滿宠进,通知其他生產(chǎn)者
produce 倉庫沒滿晕拆,通知其他生產(chǎn)者
produce 倉庫沒滿,通知其他生產(chǎn)者
produce 倉庫滿了材蹬,停止生產(chǎn)
consume 倉庫有產(chǎn)品实幕,通知其他消費(fèi)者
消費(fèi)產(chǎn)品:Produce{name='produce-67310'}
consume 倉庫有產(chǎn)品吝镣,通知其他消費(fèi)者
consume 倉庫不滿了,通知繼續(xù)生產(chǎn)
...

結(jié)果說明:
倉庫(阻塞隊列)昆庇,實現(xiàn)的關(guān)鍵有兩個地方末贾,一是倉庫產(chǎn)品數(shù)量的變更是通過AtomicInteger進(jìn)行原子操作的,即庫存的增加或減少都是按順序執(zhí)行的整吆;二是對生產(chǎn)者和消費(fèi)者進(jìn)行了分組未舟,生產(chǎn)者阻塞/喚醒在notFull監(jiān)視器上,消費(fèi)者阻塞/喚醒在notEmpty監(jiān)視器上掂为。兩組線程相互獨(dú)立裕膀,通過監(jiān)視器進(jìn)行通信,生產(chǎn)者工作的條件是倉庫不滿勇哗,停止工作的條件是倉庫已滿昼扛,阻塞等待在notFull對象上,換句話說就是欲诺,倉庫裝滿了抄谐,到notFull這個地方歇著吧!當(dāng)生產(chǎn)者把生產(chǎn)的產(chǎn)品放入倉庫后扰法,通知消費(fèi)者消費(fèi)蛹含;倉庫空了,消費(fèi)者停止工作塞颁,倉庫不滿的時候通知生產(chǎn)者浦箱。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市祠锣,隨后出現(xiàn)的幾起案子酷窥,更是在濱河造成了極大的恐慌,老刑警劉巖伴网,帶你破解...
    沈念sama閱讀 216,997評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蓬推,死亡現(xiàn)場離奇詭異,居然都是意外死亡澡腾,警方通過查閱死者的電腦和手機(jī)沸伏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來动分,“玉大人毅糟,你說我怎么就攤上這事〈汤玻” “怎么了留特?”我有些...
    開封第一講書人閱讀 163,359評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我蜕青,道長苟蹈,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,309評論 1 292
  • 正文 為了忘掉前任右核,我火速辦了婚禮慧脱,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘贺喝。我一直安慰自己菱鸥,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評論 6 390
  • 文/花漫 我一把揭開白布躏鱼。 她就那樣靜靜地躺著氮采,像睡著了一般。 火紅的嫁衣襯著肌膚如雪染苛。 梳的紋絲不亂的頭發(fā)上鹊漠,一...
    開封第一講書人閱讀 51,258評論 1 300
  • 那天,我揣著相機(jī)與錄音茶行,去河邊找鬼躯概。 笑死,一個胖子當(dāng)著我的面吹牛畔师,可吹牛的內(nèi)容都是我干的娶靡。 我是一名探鬼主播,決...
    沈念sama閱讀 40,122評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼看锉,長吁一口氣:“原來是場噩夢啊……” “哼姿锭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起度陆,我...
    開封第一講書人閱讀 38,970評論 0 275
  • 序言:老撾萬榮一對情侶失蹤艾凯,失蹤者是張志新(化名)和其女友劉穎献幔,沒想到半個月后懂傀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,403評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蜡感,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評論 3 334
  • 正文 我和宋清朗相戀三年蹬蚁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片郑兴。...
    茶點(diǎn)故事閱讀 39,769評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡犀斋,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出情连,到底是詐尸還是另有隱情叽粹,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評論 5 344
  • 正文 年R本政府宣布,位于F島的核電站虫几,受9級特大地震影響锤灿,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜辆脸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評論 3 327
  • 文/蒙蒙 一但校、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧啡氢,春花似錦状囱、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至搀崭,卻和暖如春奶栖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背门坷。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評論 1 269
  • 我被黑心中介騙來泰國打工宣鄙, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人默蚌。 一個月前我還...
    沈念sama閱讀 47,831評論 2 370
  • 正文 我出身青樓冻晤,卻偏偏與公主長得像,于是被迫代替她去往敵國和親绸吸。 傳聞我的和親對象是個殘疾皇子鼻弧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評論 2 354

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