概述
生產(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)
- 生產(chǎn)者在生產(chǎn)的時(shí)候结缚,消費(fèi)者不能消費(fèi)损晤,需要等待。
- 消費(fèi)者在消費(fèi)的時(shí)候掺冠,生產(chǎn)者不能生產(chǎn)沉馆,需要等待。
- 當(dāng)緩沖區(qū)已滿(mǎn)時(shí)德崭,生產(chǎn)者暫停生產(chǎn)斥黑,自動(dòng)阻塞;此時(shí)需要通知消費(fèi)者去消費(fèi)眉厨。
- 當(dāng)緩沖區(qū)為空時(shí)锌奴,消費(fèi)者暫停消費(fèi),自動(dòng)阻塞憾股;此時(shí)需要通知生產(chǎn)者去生產(chǎn)鹿蜀。
解決生產(chǎn)者/消費(fèi)者問(wèn)題的方法
- 采用某種機(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)。
- 在生產(chǎn)者和消費(fèi)者之間建立一個(gè)管道
以上第一種方式比較常用分冈,第二種方式見(jiàn)得不多圾另。
實(shí)現(xiàn)方式
- wait()/notify()方法
- await()/signal()方法
- BlockingQueue阻塞隊(duì)列
- 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
原文參考
感謝以下作者的分享叙量,受益匪淺~~