JAVA多線(xiàn)程-生產(chǎn)者與消費(fèi)者模型

概述

生產(chǎn)者-消費(fèi)者模型是多線(xiàn)程編程中的一個(gè)經(jīng)典模型,主要描述的是生產(chǎn)者和消費(fèi)者在同一時(shí)間段內(nèi)共用同一塊存儲(chǔ)空間(通常也稱(chēng)為緩沖區(qū),類(lèi)似于倉(cāng)庫(kù)的概念),工作時(shí),生產(chǎn)者向緩沖區(qū)去存放數(shù)據(jù)尤误,而消費(fèi)者則從緩沖區(qū)中取走數(shù)據(jù)。

特點(diǎn)

  1. 生產(chǎn)者在生產(chǎn)的時(shí)候结缚,消費(fèi)者不能消費(fèi)损晤,需要等待。
  2. 消費(fèi)者在消費(fèi)的時(shí)候掺冠,生產(chǎn)者不能生產(chǎn)沉馆,需要等待。
  3. 當(dāng)緩沖區(qū)已滿(mǎn)時(shí)德崭,生產(chǎn)者暫停生產(chǎn)斥黑,自動(dòng)阻塞;此時(shí)需要通知消費(fèi)者去消費(fèi)眉厨。
  4. 當(dāng)緩沖區(qū)為空時(shí)锌奴,消費(fèi)者暫停消費(fèi),自動(dòng)阻塞憾股;此時(shí)需要通知生產(chǎn)者去生產(chǎn)鹿蜀。

解決生產(chǎn)者/消費(fèi)者問(wèn)題的方法

  1. 采用某種機(jī)制維護(hù)生產(chǎn)者和消費(fèi)者之間的同步箕慧。比如:
<1>. 上述特點(diǎn)1和特點(diǎn)2需要通過(guò)同步來(lái)解決,比如synchronize茴恰,Lock等
<2>. 上述特點(diǎn)3和特點(diǎn)4則需要涉及到線(xiàn)程間的通信了颠焦,生產(chǎn)者線(xiàn)程生產(chǎn)數(shù)據(jù)放入緩沖區(qū)后,通知消費(fèi)者
線(xiàn)程取出數(shù)據(jù);消費(fèi)者線(xiàn)程取出數(shù)據(jù)后往枣,通知生產(chǎn)者生產(chǎn)數(shù)據(jù)伐庭,比如可以利用wait()/notify()機(jī)制來(lái)實(shí)現(xiàn)。
  1. 在生產(chǎn)者和消費(fèi)者之間建立一個(gè)管道

以上第一種方式比較常用分冈,第二種方式見(jiàn)得不多圾另。

實(shí)現(xiàn)方式

  1. wait()/notify()方法
  2. await()/signal()方法
  3. BlockingQueue阻塞隊(duì)列
  4. PipedInputStream / PipedOutputStream 管道流

以上前三個(gè)是同步機(jī)制實(shí)現(xiàn),第四個(gè)是管道方式雕沉,目前不太清楚集乔。

1. wait()/notify()方法

wait()方法:當(dāng)緩沖區(qū)已滿(mǎn)/空時(shí),生產(chǎn)者/消費(fèi)者線(xiàn)程停止自己的執(zhí)行坡椒,并且釋放鎖資源扰路,使得自己處于等待(阻塞)狀態(tài),讓其他線(xiàn)程執(zhí)行倔叼。

notify()方法:當(dāng)生產(chǎn)者/消費(fèi)者向緩沖區(qū)中放入/取出一個(gè)產(chǎn)品時(shí)幼衰,向其他等待的線(xiàn)程發(fā)出可執(zhí)行的通知,同時(shí)釋放鎖資源缀雳,使得自己處于等待狀態(tài)。

Storage.java倉(cāng)庫(kù)類(lèi):

package com.feizi.java.concurrency.model.one;

import java.util.LinkedList;

/**
 * wait()方法:當(dāng)緩沖區(qū)已滿(mǎn)/空時(shí)梢睛,生產(chǎn)者/消費(fèi)者線(xiàn)程停止自己的執(zhí)行肥印,并且釋放鎖資源,使得自己處于等待(阻塞)狀態(tài)绝葡,讓其他線(xiàn)程執(zhí)行深碱。
 * notify()方法:當(dāng)生產(chǎn)者/消費(fèi)者向緩沖區(qū)中放入/取出一個(gè)產(chǎn)品時(shí),向其他等待的線(xiàn)程發(fā)出可執(zhí)行的通知藏畅,同時(shí)釋放鎖資源敷硅,使得自己處于等待狀態(tài)。
 * Created by feizi on 2018/5/28.
 */
public class Storage {
    //倉(cāng)庫(kù)最大存儲(chǔ)量
    private static final int MAX_COUNT = 10;

    //倉(cāng)庫(kù)存儲(chǔ)的載體
    private LinkedList<Object> list = new LinkedList<>();

    /**
     * 生產(chǎn)產(chǎn)品-同步方法
     * @param producer
     */
    public synchronized void produce(String producer){
        while (list.size() == MAX_COUNT){
            System.out.println("【倉(cāng)庫(kù)已滿(mǎn)】愉阎," + producer + ":暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)...");
            try {
                //倉(cāng)庫(kù)已滿(mǎn)绞蹦,暫不生產(chǎn),生產(chǎn)阻塞
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //生產(chǎn)產(chǎn)品
        list.add(new Object());
        System.out.println( producer + ":=====》生產(chǎn)了一個(gè)產(chǎn)品\t榜旦,【倉(cāng)庫(kù)儲(chǔ)量】為:" + list.size());
        notifyAll();
    }

    /**
     * 消費(fèi)產(chǎn)品-同步方法
     * @param consumer
     */
    public synchronized void consume(String consumer){
        while (list.size() == 0){
            System.out.println("【倉(cāng)庫(kù)已空】幽七, " + consumer + ":暫不消費(fèi)...");
            try {
                //倉(cāng)庫(kù)已空,暫不消費(fèi)溅呢,消費(fèi)阻塞
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        //消費(fèi)產(chǎn)品
        list.remove();
        System.out.println(consumer + ":================》消費(fèi)了一個(gè)產(chǎn)品\t澡屡,【倉(cāng)庫(kù)儲(chǔ)量】為:" + list.size());
        notifyAll();
    }

    /**
     * 生產(chǎn)產(chǎn)品-同步塊
     * @param producer
     */
    public void produce1(String producer){
        synchronized (list){
            while (list.size() == MAX_COUNT){
                try {
                    System.out.println("【倉(cāng)庫(kù)已滿(mǎn)】猿挚," + producer + ":暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)...");
                    //倉(cāng)庫(kù)已滿(mǎn),暫不生產(chǎn)驶鹉,生產(chǎn)阻塞
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //生產(chǎn)產(chǎn)品
            list.add(new Object());
            System.out.println( producer + ":=====》生產(chǎn)了一個(gè)產(chǎn)品\t绩蜻,【倉(cāng)庫(kù)儲(chǔ)量】為:" + list.size());
            list.notifyAll();
        }
    }

    /**
     * 消費(fèi)產(chǎn)品-同步塊
     * @param consumer
     */
    public void consume1(String consumer){
        synchronized (list){
            while (list.size() == 0){
                try {
                    System.out.println("【倉(cāng)庫(kù)已空】, " + consumer + ":暫不消費(fèi)...");
                    //倉(cāng)庫(kù)已空室埋,暫不消費(fèi)办绝,消費(fèi)阻塞
                    list.wait();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //消費(fèi)產(chǎn)品
            list.remove();
            System.out.println(consumer + ":================》消費(fèi)了一個(gè)產(chǎn)品\t,【倉(cāng)庫(kù)儲(chǔ)量】為:" + list.size());
            list.notifyAll();
        }
    }
}

Producer.java生產(chǎn)者類(lèi):

package com.feizi.java.concurrency.model.one;

import java.util.concurrent.TimeUnit;

/**
 * Created by feizi on 2018/5/28.
 */
public class Producer implements Runnable {
    /*生產(chǎn)者名稱(chēng)*/
    private String name;
    /*倉(cāng)庫(kù)*/
    private Storage storage;

    public Producer(String name, Storage storage) {
        this.name = name;
        this.storage = storage;
    }

    @Override
    public void run() {
        while (true){
            try {
                storage.produce(name);
//                storage.produce1(name);
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Consumer.java消費(fèi)者類(lèi):

package com.feizi.java.concurrency.model.one;

import java.util.concurrent.TimeUnit;

/**
 * Created by feizi on 2018/5/28.
 */
public class Consumer implements Runnable {
    /*消費(fèi)者名稱(chēng)*/
    private String name;
    /*倉(cāng)庫(kù)*/
    private Storage storage;

    public Consumer(String name, Storage storage) {
        this.name = name;
        this.storage = storage;
    }

    @Override
    public void run() {
        while (true){
            try {
                TimeUnit.MILLISECONDS.sleep(2500);
                storage.consume(name);
//                storage.consume1(name);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

TestOne.java測(cè)試類(lèi):

package com.feizi.java.concurrency.model.one;

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

/**
 * Created by feizi on 2018/5/28.
 */
public class TestOne {
    public static void main(String[] args) {
        Storage storage = new Storage();
        /*for (int i = 0; i < 2; i++){
            new Thread(new Producer("生產(chǎn)者【" + i + "】", storage)).start();
        }

        for (int i = 0; i < 5; i++){
            new Thread(new Consumer("消費(fèi)者【" + i + "】" , storage)).start();
        }*/

        ExecutorService threadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 2; i++){
            threadPool.execute(new Producer("生產(chǎn)者【" + i + "】", storage));
        }

        for (int i = 0; i < 5; i++){
            threadPool.execute(new Consumer("消費(fèi)者【" + i + "】" , storage));
        }

        threadPool.shutdown();
    }
}

控制臺(tái)輸出結(jié)果:

生產(chǎn)者【1】:=====》生產(chǎn)了一個(gè)產(chǎn)品    词顾,【倉(cāng)庫(kù)儲(chǔ)量】為:1
生產(chǎn)者【0】:=====》生產(chǎn)了一個(gè)產(chǎn)品    八秃,【倉(cāng)庫(kù)儲(chǔ)量】為:2
生產(chǎn)者【1】:=====》生產(chǎn)了一個(gè)產(chǎn)品    ,【倉(cāng)庫(kù)儲(chǔ)量】為:3
生產(chǎn)者【0】:=====》生產(chǎn)了一個(gè)產(chǎn)品    肉盹,【倉(cāng)庫(kù)儲(chǔ)量】為:4
消費(fèi)者【0】:================》消費(fèi)了一個(gè)產(chǎn)品 昔驱,【倉(cāng)庫(kù)儲(chǔ)量】為:3
消費(fèi)者【5】:================》消費(fèi)了一個(gè)產(chǎn)品 ,【倉(cāng)庫(kù)儲(chǔ)量】為:2
消費(fèi)者【3】:================》消費(fèi)了一個(gè)產(chǎn)品 上忍,【倉(cāng)庫(kù)儲(chǔ)量】為:1
消費(fèi)者【4】:================》消費(fèi)了一個(gè)產(chǎn)品 骤肛,【倉(cāng)庫(kù)儲(chǔ)量】為:0
【倉(cāng)庫(kù)已空】, 消費(fèi)者【1】:暫不消費(fèi)...
【倉(cāng)庫(kù)已空】窍蓝, 消費(fèi)者【2】:暫不消費(fèi)...
生產(chǎn)者【0】:=====》生產(chǎn)了一個(gè)產(chǎn)品    腋颠,【倉(cāng)庫(kù)儲(chǔ)量】為:1
消費(fèi)者【2】:================》消費(fèi)了一個(gè)產(chǎn)品 ,【倉(cāng)庫(kù)儲(chǔ)量】為:0
【倉(cāng)庫(kù)已空】吓笙, 消費(fèi)者【1】:暫不消費(fèi)...
生產(chǎn)者【1】:=====》生產(chǎn)了一個(gè)產(chǎn)品    淑玫,【倉(cāng)庫(kù)儲(chǔ)量】為:1
消費(fèi)者【1】:================》消費(fèi)了一個(gè)產(chǎn)品 ,【倉(cāng)庫(kù)儲(chǔ)量】為:0

2.await() / signal()方法

await()和signal()的功能基本上和wait()/notify()類(lèi)似面睛,完全可以取代它們絮蒿,但是它們和新引入的鎖定機(jī)制Lock直接掛鉤,具有更強(qiáng)的靈活性叁鉴,通過(guò)在Lock對(duì)象上調(diào)用newCondition()方法土涝,將條件變量和一個(gè)鎖對(duì)象進(jìn)行綁定,進(jìn)而控制并發(fā)程序訪問(wèn)競(jìng)爭(zhēng)資源的安全幌墓。

Storage.java倉(cāng)庫(kù)類(lèi):

package com.feizi.java.concurrency.model.two;

import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * await()和signal()的功能基本上和wait()/notify()類(lèi)似但壮,完全可以取代它們,但是它們和新引入的鎖定機(jī)制Lock直接掛鉤常侣,具有更強(qiáng)的靈活性蜡饵,
 * 通過(guò)在Lock對(duì)象上調(diào)用newCondition()方法,將條件變量和一個(gè)鎖對(duì)象進(jìn)行綁定袭祟,進(jìn)而控制并發(fā)程序訪問(wèn)競(jìng)爭(zhēng)資源的安全
 * Created by feizi on 2018/5/28.
 */
public class Storage {
    //倉(cāng)庫(kù)最大存儲(chǔ)量
    private static final int MAX_COUNT = 10;

    //倉(cāng)庫(kù)存儲(chǔ)的載體
    private LinkedList<Object> list = new LinkedList<>();

    //可重入鎖
    private final Lock lock = new ReentrantLock();

    //倉(cāng)庫(kù)滿(mǎn)的條件變量
    private final Condition full = lock.newCondition();

    //倉(cāng)庫(kù)空的條件變量
    private final Condition empty = lock.newCondition();

    /**
     * 生產(chǎn)產(chǎn)品
     * @param producer
     */
    public void produce(String producer){
        try {
            //獲得鎖
            lock.lock();
            while (list.size() == MAX_COUNT){
                try {
                    System.out.println("倉(cāng)庫(kù)已滿(mǎn)验残,【" + producer + "】:暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)...");
                    //由于倉(cāng)庫(kù)已滿(mǎn),暫不生產(chǎn),生產(chǎn)阻塞
                    full.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //生產(chǎn)產(chǎn)品
            list.add(new Object());

            System.out.println("===>【" + producer + "】:生產(chǎn)了一個(gè)產(chǎn)品您没,\t【倉(cāng)庫(kù)儲(chǔ)量】為:" + list.size());

            empty.signalAll();
        } finally {
            //釋放鎖
            lock.unlock();
        }
    }

    /**
     * 消費(fèi)產(chǎn)品
     * @param consumer
     */
    public void consume(String consumer){
        try {
            //獲得鎖
            lock.lock();

            while (list.size() == 0){
                try {
                    System.out.println("倉(cāng)庫(kù)已空鸟召,【" + consumer + "】:暫時(shí)不能執(zhí)行消費(fèi)任務(wù)...");
                    //由于倉(cāng)庫(kù)已空,暫不消費(fèi)氨鹏,消費(fèi)阻塞
                    empty.await();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            //消費(fèi)產(chǎn)品
            list.remove();

            System.out.println("=============>【" + consumer + "】:消費(fèi)了一個(gè)產(chǎn)品欧募,\t【倉(cāng)庫(kù)儲(chǔ)量】為:" + list.size());
            full.signalAll();
        }finally {
            //釋放鎖
            lock.unlock();
        }
    }
}

Producer.java生產(chǎn)者類(lèi):

package com.feizi.java.concurrency.model.two;

import java.util.concurrent.TimeUnit;

/**
 * Created by feizi on 2018/5/28.
 */
public class Producer implements Runnable {
    private String name;

    private Storage storage;

    public Producer(String name, Storage storage) {
        this.name = name;
        this.storage = storage;
    }

    @Override
    public void run() {
        while (true){
            try {
                TimeUnit.SECONDS.sleep(1);
                storage.produce(name);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Consumer.java消費(fèi)者類(lèi):

package com.feizi.java.concurrency.model.two;

import java.util.concurrent.TimeUnit;

/**
 * Created by feizi on 2018/5/28.
 */
public class Consumer implements Runnable {
    private String name;

    private Storage storage;

    public Consumer(String name, Storage storage) {
        this.name = name;
        this.storage = storage;
    }

    @Override
    public void run() {
        while (true){
            try {
                TimeUnit.SECONDS.sleep(2);
                storage.consume(name);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

TestTwo.java測(cè)試類(lèi):

package com.feizi.java.concurrency.model.two;


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

/**
 * Created by feizi on 2018/5/28.
 */
public class TestTwo {
    public static void main(String[] args) {
        Storage storage = new Storage();

        ExecutorService threadPool = Executors.newCachedThreadPool();
        for (int i = 0; i < 2; i++){
            threadPool.execute(new Producer("生產(chǎn)者" + i, storage));
        }

        for (int i = 0; i < 4; i++){
            threadPool.execute(new Consumer("消費(fèi)者" + i, storage));
        }

        threadPool.shutdown();
    }
}

控制臺(tái)輸出結(jié)果:

===>【生產(chǎn)者3】:生產(chǎn)了一個(gè)產(chǎn)品, 【倉(cāng)庫(kù)儲(chǔ)量】為:1
===>【生產(chǎn)者0】:生產(chǎn)了一個(gè)產(chǎn)品仆抵, 【倉(cāng)庫(kù)儲(chǔ)量】為:2
===>【生產(chǎn)者4】:生產(chǎn)了一個(gè)產(chǎn)品跟继, 【倉(cāng)庫(kù)儲(chǔ)量】為:3
===>【生產(chǎn)者2】:生產(chǎn)了一個(gè)產(chǎn)品, 【倉(cāng)庫(kù)儲(chǔ)量】為:4
===>【生產(chǎn)者1】:生產(chǎn)了一個(gè)產(chǎn)品镣丑, 【倉(cāng)庫(kù)儲(chǔ)量】為:5
===>【生產(chǎn)者1】:生產(chǎn)了一個(gè)產(chǎn)品舔糖, 【倉(cāng)庫(kù)儲(chǔ)量】為:6
=============>【消費(fèi)者0】:消費(fèi)了一個(gè)產(chǎn)品,   【倉(cāng)庫(kù)儲(chǔ)量】為:5
===>【生產(chǎn)者3】:生產(chǎn)了一個(gè)產(chǎn)品莺匠, 【倉(cāng)庫(kù)儲(chǔ)量】為:6
===>【生產(chǎn)者4】:生產(chǎn)了一個(gè)產(chǎn)品金吗, 【倉(cāng)庫(kù)儲(chǔ)量】為:7
===>【生產(chǎn)者2】:生產(chǎn)了一個(gè)產(chǎn)品, 【倉(cāng)庫(kù)儲(chǔ)量】為:8
===>【生產(chǎn)者0】:生產(chǎn)了一個(gè)產(chǎn)品趣竣, 【倉(cāng)庫(kù)儲(chǔ)量】為:9
=============>【消費(fèi)者1】:消費(fèi)了一個(gè)產(chǎn)品摇庙,   【倉(cāng)庫(kù)儲(chǔ)量】為:8
===>【生產(chǎn)者1】:生產(chǎn)了一個(gè)產(chǎn)品, 【倉(cāng)庫(kù)儲(chǔ)量】為:9
===>【生產(chǎn)者4】:生產(chǎn)了一個(gè)產(chǎn)品遥缕, 【倉(cāng)庫(kù)儲(chǔ)量】為:10
倉(cāng)庫(kù)已滿(mǎn)卫袒,【生產(chǎn)者0】:暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)...
倉(cāng)庫(kù)已滿(mǎn),【生產(chǎn)者3】:暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)...

3.BlockingQueue阻塞隊(duì)列

BlockingQueue是一個(gè)已經(jīng)在內(nèi)部實(shí)現(xiàn)了同步的阻塞隊(duì)列(由鏈表結(jié)構(gòu)組成的有界阻塞隊(duì)列)单匣,實(shí)現(xiàn)方式采用的是await()/signal()方法夕凝,可以在生成對(duì)象時(shí)指定容量大小,用于阻塞操作的是put()和take()方法户秤。

put()方法:類(lèi)似于前面的生產(chǎn)者線(xiàn)程迹冤,容量達(dá)到最大時(shí),自動(dòng)阻塞

take()方法:類(lèi)似于前面的消費(fèi)者線(xiàn)程虎忌,容量為0時(shí),啟動(dòng)阻塞

Storage.java倉(cāng)庫(kù)類(lèi):

package com.feizi.java.concurrency.model.three;

import java.util.concurrent.LinkedBlockingQueue;

/**
 * BlockingQueue是一個(gè)已經(jīng)在內(nèi)部實(shí)現(xiàn)了同步的阻塞隊(duì)列橱鹏,實(shí)現(xiàn)方式采用的是await()/signal()方法膜蠢,
 * 可以在生成對(duì)象時(shí)指定容量大小,用于阻塞操作的是put()和take()方法
 * put()方法:類(lèi)似于前面的生產(chǎn)者線(xiàn)程莉兰,容量達(dá)到最大時(shí)挑围,自動(dòng)阻塞
 * take()方法:類(lèi)似于前面的消費(fèi)者線(xiàn)程,容量為0時(shí)糖荒,啟動(dòng)阻塞
 * Created by feizi on 2018/5/28.
 */
public class Storage {
    //倉(cāng)庫(kù)最大存儲(chǔ)量
    private static final int MAX_COUNT = 10;

    //倉(cāng)庫(kù)存儲(chǔ)的載體
    private LinkedBlockingQueue<Object> list = new LinkedBlockingQueue<>(10);

    /**
     * 生產(chǎn)產(chǎn)品
     * @param producer
     */
    public void produce(String producer){
        //如果倉(cāng)庫(kù)已滿(mǎn)
        if(list.size() == MAX_COUNT){
            System.out.println("倉(cāng)庫(kù)已滿(mǎn)杉辙,【" + producer + "】:暫時(shí)不能執(zhí)行生產(chǎn)任務(wù)...");
        }

        try {
            //生產(chǎn)產(chǎn)品
            list.put(new Object());
            System.out.println("===>【" + producer + "】:生產(chǎn)了一個(gè)產(chǎn)品,\t【倉(cāng)庫(kù)儲(chǔ)量】為:" + list.size());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 消費(fèi)產(chǎn)品
     * @param consumer
     */
    public void consume(String consumer){
        //如果倉(cāng)庫(kù)已空
        if (list.size() == 0){
            System.out.println("倉(cāng)庫(kù)已空捶朵,【" + consumer + "】:暫時(shí)不能執(zhí)行消費(fèi)任務(wù)...");
        }

        try {
            //消費(fèi)產(chǎn)品
            list.take();
            System.out.println("================>【" + consumer + "】:消費(fèi)了一個(gè)產(chǎn)品蜘矢,\t【倉(cāng)庫(kù)儲(chǔ)量】為:" + list.size());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }
}

Producer.java生產(chǎn)者類(lèi):

package com.feizi.java.concurrency.model.three;

import java.util.concurrent.TimeUnit;

/**
 * Created by feizi on 2018/5/28.
 */
public class Producer implements Runnable {
    private String name;
    private Storage storage;

    public Producer(String name, Storage storage) {
        this.name = name;
        this.storage = storage;
    }

    @Override
    public void run() {
        while (true){
            try {
                TimeUnit.SECONDS.sleep(1);
                storage.produce(name);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Consumer.java消費(fèi)者類(lèi):

package com.feizi.java.concurrency.model.three;

import java.util.concurrent.TimeUnit;

/**
 * Created by feizi on 2018/5/28.
 */
public class Consumer implements Runnable {
    private String name;
    private Storage storage;

    public Consumer(String name, Storage storage) {
        this.name = name;
        this.storage = storage;
    }

    @Override
    public void run() {
        while (true){
            try {
                TimeUnit.SECONDS.sleep(2);
                storage.consume(name);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

TestThree.java測(cè)試類(lèi):

package com.feizi.java.concurrency.model.three;

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

/**
 * Created by feizi on 2018/5/28.
 */
public class TestThree {
    public static void main(String[] args) {
        Storage storage = new Storage();

        ExecutorService threadPool = Executors.newCachedThreadPool();

        for (int i = 0; i < 3; i++){
            threadPool.execute(new Producer("生產(chǎn)者" + i, storage));
        }

        for (int j = 0; j < 5; j++){
            threadPool.execute(new Consumer("消費(fèi)者" + j, storage));
        }
    }
}

控制臺(tái)輸出結(jié)果:

===>【生產(chǎn)者2】:生產(chǎn)了一個(gè)產(chǎn)品狂男, 【倉(cāng)庫(kù)儲(chǔ)量】為:1
===>【生產(chǎn)者1】:生產(chǎn)了一個(gè)產(chǎn)品, 【倉(cāng)庫(kù)儲(chǔ)量】為:2
===>【生產(chǎn)者0】:生產(chǎn)了一個(gè)產(chǎn)品品腹, 【倉(cāng)庫(kù)儲(chǔ)量】為:3
===>【生產(chǎn)者1】:生產(chǎn)了一個(gè)產(chǎn)品岖食, 【倉(cāng)庫(kù)儲(chǔ)量】為:4
===>【生產(chǎn)者2】:生產(chǎn)了一個(gè)產(chǎn)品, 【倉(cāng)庫(kù)儲(chǔ)量】為:5
===>【生產(chǎn)者0】:生產(chǎn)了一個(gè)產(chǎn)品, 【倉(cāng)庫(kù)儲(chǔ)量】為:6
================>【消費(fèi)者4】:消費(fèi)了一個(gè)產(chǎn)品,    【倉(cāng)庫(kù)儲(chǔ)量】為:5
================>【消費(fèi)者0】:消費(fèi)了一個(gè)產(chǎn)品滥朱,    【倉(cāng)庫(kù)儲(chǔ)量】為:4
================>【消費(fèi)者1】:消費(fèi)了一個(gè)產(chǎn)品滞谢,    【倉(cāng)庫(kù)儲(chǔ)量】為:3
================>【消費(fèi)者2】:消費(fèi)了一個(gè)產(chǎn)品,    【倉(cāng)庫(kù)儲(chǔ)量】為:2
================>【消費(fèi)者3】:消費(fèi)了一個(gè)產(chǎn)品伐蒂,    【倉(cāng)庫(kù)儲(chǔ)量】為:1
===>【生產(chǎn)者1】:生產(chǎn)了一個(gè)產(chǎn)品, 【倉(cāng)庫(kù)儲(chǔ)量】為:2
===>【生產(chǎn)者0】:生產(chǎn)了一個(gè)產(chǎn)品, 【倉(cāng)庫(kù)儲(chǔ)量】為:3
===>【生產(chǎn)者2】:生產(chǎn)了一個(gè)產(chǎn)品存和, 【倉(cāng)庫(kù)儲(chǔ)量】為:4
===>【生產(chǎn)者2】:生產(chǎn)了一個(gè)產(chǎn)品, 【倉(cāng)庫(kù)儲(chǔ)量】為:5
===>【生產(chǎn)者1】:生產(chǎn)了一個(gè)產(chǎn)品赶舆, 【倉(cāng)庫(kù)儲(chǔ)量】為:6
===>【生產(chǎn)者0】:生產(chǎn)了一個(gè)產(chǎn)品哑姚, 【倉(cāng)庫(kù)儲(chǔ)量】為:7
================>【消費(fèi)者4】:消費(fèi)了一個(gè)產(chǎn)品,    【倉(cāng)庫(kù)儲(chǔ)量】為:6
================>【消費(fèi)者0】:消費(fèi)了一個(gè)產(chǎn)品芜茵,    【倉(cāng)庫(kù)儲(chǔ)量】為:5

原文參考

感謝以下作者的分享叙量,受益匪淺~~

  1. https://www.cnblogs.com/Ming8006/p/7243858.html
  2. https://www.cnblogs.com/xrq730/p/4855663.html
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市九串,隨后出現(xiàn)的幾起案子绞佩,更是在濱河造成了極大的恐慌,老刑警劉巖猪钮,帶你破解...
    沈念sama閱讀 222,627評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件品山,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡烤低,警方通過(guò)查閱死者的電腦和手機(jī)肘交,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)扑馁,“玉大人涯呻,你說(shuō)我怎么就攤上這事∧逡” “怎么了复罐?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,346評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)雄家。 經(jīng)常有香客問(wèn)我效诅,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,097評(píng)論 1 300
  • 正文 為了忘掉前任乱投,我火速辦了婚禮咽笼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘篡腌。我一直安慰自己褐荷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布嘹悼。 她就那樣靜靜地躺著叛甫,像睡著了一般。 火紅的嫁衣襯著肌膚如雪杨伙。 梳的紋絲不亂的頭發(fā)上其监,一...
    開(kāi)封第一講書(shū)人閱讀 52,696評(píng)論 1 312
  • 那天,我揣著相機(jī)與錄音限匣,去河邊找鬼抖苦。 笑死,一個(gè)胖子當(dāng)著我的面吹牛米死,可吹牛的內(nèi)容都是我干的锌历。 我是一名探鬼主播,決...
    沈念sama閱讀 41,165評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼峦筒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼究西!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起物喷,我...
    開(kāi)封第一講書(shū)人閱讀 40,108評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤卤材,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后峦失,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體扇丛,經(jīng)...
    沈念sama閱讀 46,646評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評(píng)論 3 342
  • 正文 我和宋清朗相戀三年尉辑,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了帆精。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,861評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡隧魄,死狀恐怖实幕,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情堤器,我是刑警寧澤,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布末贾,位于F島的核電站闸溃,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜辉川,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評(píng)論 3 336
  • 文/蒙蒙 一表蝙、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧乓旗,春花似錦府蛇、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,698評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至妆距,卻和暖如春穷遂,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背娱据。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,804評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工蚪黑, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人中剩。 一個(gè)月前我還...
    沈念sama閱讀 49,287評(píng)論 3 379
  • 正文 我出身青樓忌穿,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親结啼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子掠剑,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評(píng)論 2 361

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