使用多個(gè)線程除了并發(fā)進(jìn)行提高一個(gè)大任務(wù)或者多個(gè)子任務(wù)的執(zhí)行效率,多線程之間還存在協(xié)作完成任務(wù)涧偷,共同協(xié)作完成任務(wù)涉及到多線程之間的通訊戳稽。生產(chǎn)者消費(fèi)者模型就是典型的多線程協(xié)作的應(yīng)用
是什么:
什么是線程間的協(xié)作
- 多線程協(xié)作即多線程之間通過多線程通訊技術(shù)筹陵,實(shí)現(xiàn)多線程按照特定順序共同協(xié)作完成一項(xiàng)任務(wù)益老。
怎么用:
多線程協(xié)作用在哪
- 多線程協(xié)作場景有多種使用場景,典型的有線程通過通知機(jī)制交替進(jìn)行的生產(chǎn)者消費(fèi)者模型:生產(chǎn)者生產(chǎn)物品,生產(chǎn)完通知消費(fèi)者進(jìn)行消費(fèi)悲立,消費(fèi)者收到通知后進(jìn)行消費(fèi)鹿寨,消費(fèi)完再通知生產(chǎn)者進(jìn)行生產(chǎn);
- 多個(gè)線程共同等待一齊完成后集體進(jìn)行下一步薪夕,以此循環(huán)共同推進(jìn)的循環(huán)路障模型
- 某個(gè)線程任務(wù)等待多個(gè)線程都就緒后才開始的倒計(jì)時(shí)門閘模型
用什么實(shí)現(xiàn)生產(chǎn)者消費(fèi)者模型
- 使用objcet的自帶的wait脚草,notify,notifyAll方法進(jìn)行線程間的通知等待機(jī)制原献,需要注意馏慨,這幾個(gè)方法必須在synchronized的同步代碼塊的范圍內(nèi)使用,否則會拋異常姑隅。
public class ProduceConsumeDemo {
public static void main(String[] args) {
List<String> container=new ArrayList<>();
ExecutorService executorService= Executors.newFixedThreadPool(2);
executorService.submit(new Consumer(container));
executorService.submit(new Producer(container));
executorService.shutdown();
}
}
@Slf4j
class Consumer implements Runnable{
int money=0;
private List<String> container;
public Consumer(List<String> container){
this.container=container;
}
void consumeFood() throws Exception{
while (money<15){
synchronized (container){
log.debug("container owner is consumer,money is {}",money);
if(container.size()==0){
container.wait();
}
Iterator it=container.iterator();
while(it.hasNext()){
money++;
log.debug("wow,the {} is delicious写隶!nice food!",it.next());
it.remove();
}
log.debug(" container is empty,it is time to cook!");
container.notifyAll();
log.debug("consume notified continue");
}
}
log.debug("consumer money cost =15,over");
}
@Override
public void run() {
try {
consumeFood();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Slf4j
class Producer implements Runnable{
private String[] dishes={"rice","beef","chicken","tomato","potato"};
int money=0;
private Random random=new Random();
private List<String> container;
public Producer(List<String> container){
this.container=container;
}
void produceFood() throws Exception{
while (money<15){
synchronized (container){
log.debug("container owner is produce,money is {}",money);
if(container.size()>=5){
container.wait();
}
while(container.size()<5){
String dish=dishes[random.nextInt(5)];
log.debug("new food is cooked,it is {}",dish);
container.add(dish);
money++;
}
log.debug(" container is full,it is time to eat");
// 做完后喚醒其他
container.notifyAll();
log.debug("produce notified continue");
}
}
log.debug("producer money cost =15,over");
}
@Override
public void run() {
try {
produceFood();
} catch (Exception e) {
e.printStackTrace();
}
}
}
打印如下:
19:54:05.007 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - container owner is consumer,money is 0
19:54:05.011 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - container owner is produce,money is 0
19:54:05.011 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - new food is cooked,it is rice
19:54:05.011 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - new food is cooked,it is beef
19:54:05.011 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - new food is cooked,it is potato
19:54:05.012 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - new food is cooked,it is potato
19:54:05.012 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - new food is cooked,it is tomato
19:54:05.012 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - container is full,it is time to eat
19:54:05.012 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - produce notified continue
19:54:05.012 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - container owner is produce,money is 5
19:54:05.012 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - wow,the rice is delicious粤策!nice food樟澜!
19:54:05.012 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - wow,the beef is delicious误窖!nice food叮盘!
19:54:05.012 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - wow,the potato is delicious!nice food霹俺!
19:54:05.012 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - wow,the potato is delicious柔吼!nice food!
19:54:05.012 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - wow,the tomato is delicious丙唧!nice food愈魏!
19:54:05.012 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - container is empty,it is time to cook!
19:54:05.012 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - consume notified continue
19:54:05.012 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - container owner is consumer,money is 5
19:54:05.012 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - new food is cooked,it is tomato
19:54:05.012 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - new food is cooked,it is chicken
19:54:05.012 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - new food is cooked,it is chicken
19:54:05.012 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - new food is cooked,it is tomato
19:54:05.012 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - new food is cooked,it is rice
19:54:05.012 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - container is full,it is time to eat
19:54:05.012 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - produce notified continue
19:54:05.012 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - container owner is produce,money is 10
19:54:05.012 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - wow,the tomato is delicious!nice food想际!
19:54:05.012 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - wow,the chicken is delicious培漏!nice food!
19:54:05.012 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - wow,the chicken is delicious胡本!nice food牌柄!
19:54:05.013 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - wow,the tomato is delicious!nice food侧甫!
19:54:05.013 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - wow,the rice is delicious珊佣!nice food!
19:54:05.013 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - container is empty,it is time to cook!
19:54:05.013 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - consume notified continue
19:54:05.013 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - container owner is consumer,money is 10
19:54:05.013 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - new food is cooked,it is tomato
19:54:05.013 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - new food is cooked,it is beef
19:54:05.013 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - new food is cooked,it is rice
19:54:05.013 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - new food is cooked,it is tomato
19:54:05.013 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - new food is cooked,it is tomato
19:54:05.013 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - container is full,it is time to eat
19:54:05.013 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - produce notified continue
19:54:05.013 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.Producer - producer money cost =15,over
19:54:05.013 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - wow,the tomato is delicious披粟!nice food咒锻!
19:54:05.013 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - wow,the beef is delicious!nice food守屉!
19:54:05.013 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - wow,the rice is delicious惑艇!nice food!
19:54:05.013 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - wow,the tomato is delicious拇泛!nice food滨巴!
19:54:05.013 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - wow,the tomato is delicious须板!nice food!
19:54:05.013 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - container is empty,it is time to cook!
19:54:05.013 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - consume notified continue
19:54:05.013 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.Consumer - consumer money cost =15,over
- 使用并發(fā)隊(duì)列BlockingQueue兢卵,BlockingQueue本身就是為生產(chǎn)者消費(fèi)者模型設(shè)計(jì)的線程安全的并發(fā)容器习瑰,使用起來簡單高效。
@Slf4j
public class ProduceConsumerQueueDemo {
public static void main(String[] args) throws Exception{
BlockingQueue<String> queue=new LinkedBlockingDeque<>(5);
Random random=new Random();
List<String> foods= Arrays.asList("beef","nice","meat","tomato","potato");
ExecutorService executorService= Executors.newCachedThreadPool();
CountDownLatch countDownLatch=new CountDownLatch(2);
executorService.execute(()->{
int i=0;
String food;
while(i<15){
try {
food=queue.poll(10L, TimeUnit.SECONDS);
log.debug("delicious food秽荤,i like the {},size is {}",food,queue.size());
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
countDownLatch.countDown();
log.debug("eat over!");
});
executorService.execute(()->{
int i=0;
String food;
while(i<15){
try {
food=foods.get(random.nextInt(5));
queue.offer(food,10L, TimeUnit.SECONDS);
log.debug("delicious food is cooked {},queue size is {}",food,queue.size());
i++;
} catch (InterruptedException e) {
e.printStackTrace();
}
}
countDownLatch.countDown();
log.debug("cook over!");
});
countDownLatch.await();
log.debug("main over!");
executorService.shutdown();
}
}
打印結(jié)果如下:
20:24:04.513 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food is cooked tomato,queue size is 1
20:24:04.513 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food甜奄,i like the tomato,size is 0
20:24:04.516 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food,i like the beef,size is 0
20:24:04.516 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food is cooked beef,queue size is 1
20:24:04.516 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food is cooked nice,queue size is 1
20:24:04.516 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food窃款,i like the nice,size is 0
20:24:04.516 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food is cooked beef,queue size is 1
20:24:04.516 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food is cooked beef,queue size is 1
20:24:04.516 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food课兄,i like the beef,size is 0
20:24:04.516 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food is cooked tomato,queue size is 2
20:24:04.516 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food,i like the beef,size is 1
20:24:04.516 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food is cooked beef,queue size is 2
20:24:04.516 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food晨继,i like the tomato,size is 1
20:24:04.516 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food is cooked beef,queue size is 2
20:24:04.516 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food烟阐,i like the beef,size is 1
20:24:04.516 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food is cooked tomato,queue size is 2
20:24:04.516 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food,i like the beef,size is 1
20:24:04.516 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food is cooked nice,queue size is 2
20:24:04.516 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food紊扬,i like the tomato,size is 1
20:24:04.516 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food is cooked nice,queue size is 2
20:24:04.517 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food is cooked nice,queue size is 2
20:24:04.517 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food蜒茄,i like the nice,size is 1
20:24:04.517 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food is cooked potato,queue size is 3
20:24:04.517 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food,i like the nice,size is 2
20:24:04.517 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food is cooked meat,queue size is 3
20:24:04.517 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food餐屎,i like the nice,size is 2
20:24:04.517 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food is cooked tomato,queue size is 3
20:24:04.517 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food檀葛,i like the potato,size is 2
20:24:04.517 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food,i like the meat,size is 1
20:24:04.517 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - cook over!
20:24:04.517 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - delicious food腹缩,i like the tomato,size is 0
20:24:04.517 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - eat over!
20:24:04.517 [main] DEBUG com.dz.demo.multiThread.ProduceConsumerQueueDemo - main over!
- 使用LockSupport相關(guān)park與unpark方法屿聋,park方法使當(dāng)前線程需要一個(gè)令牌才能繼續(xù)(該令牌可以在park之前就被有或者park后被其他線程發(fā)放),unpark方法是給對應(yīng)線程發(fā)放一個(gè)令牌藏鹊。
public class ProduceConsumeLockSupportDemo {
public static void main(String[] args) throws Exception{
List<String>container=new ArrayList<>(5);
Map<String,Thread> threadMap=new ConcurrentHashMap<>();
ExecutorService executorService= Executors.newFixedThreadPool(2);
executorService.execute(new LockSupportProducer(threadMap,container));
executorService.execute(new LockSupportConsumer(threadMap,container));
executorService.shutdown();
}
}
@Slf4j
class LockSupportProducer implements Runnable{
private Map<String,Thread> threadMap;
private List<String>container;
public LockSupportProducer(Map<String,Thread> threadMap,List<String>container){
this.threadMap=threadMap;
this.container=container;
}
private int money=0;
private String[] dishes={"rice","beef","chicken","tomato","potato"};
private Random random=new Random();
@Override
public void run() {
threadMap.put("producer",Thread.currentThread());
while(money<15){
if(container.size()<5){
String food=dishes[random.nextInt(5)];
log.debug("cooking ,this time food is {},time is {}",food,money);
container.add(food);
money++;
}else {
LockSupport.unpark(threadMap.get("consumer"));
LockSupport.park();
}
}
LockSupport.unpark(threadMap.get("consumer"));
log.debug("cooking over润讥,time is {}",money);
}
}
@Slf4j
class LockSupportConsumer implements Runnable{
private Map<String,Thread> threadMap;
private List<String>container;
private int money=0;
public LockSupportConsumer(Map<String,Thread> threadMap,List<String>container){
this.threadMap=threadMap;
this.container=container;
}
@Override
public void run() {
threadMap.put("consumer",Thread.currentThread());
while(money<15){
if(container.size()>0){
Iterator<String> it=container.iterator();
while (it.hasNext()){
String food=it.next();
it.remove();
log.debug("eating ,delicious food is {},time is {}",food,money);
money++;
}
}else {
LockSupport.unpark(threadMap.get("producer"));
LockSupport.park();
}
}
log.debug("eating over,time is {}",money);
}
}
打印結(jié)果如下:
20:30:03.768 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking ,this time food is chicken,time is 0
20:30:03.772 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking ,this time food is rice,time is 1
20:30:03.772 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking ,this time food is beef,time is 2
20:30:03.772 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking ,this time food is beef,time is 3
20:30:03.772 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking ,this time food is potato,time is 4
20:30:03.772 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating ,delicious food is chicken,time is 0
20:30:03.772 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating ,delicious food is rice,time is 1
20:30:03.772 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating ,delicious food is beef,time is 2
20:30:03.772 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating ,delicious food is beef,time is 3
20:30:03.772 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating ,delicious food is potato,time is 4
20:30:03.772 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking ,this time food is potato,time is 5
20:30:03.772 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking ,this time food is chicken,time is 6
20:30:03.772 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking ,this time food is potato,time is 7
20:30:03.772 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking ,this time food is potato,time is 8
20:30:03.772 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking ,this time food is chicken,time is 9
20:30:03.772 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating ,delicious food is potato,time is 5
20:30:03.772 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating ,delicious food is chicken,time is 6
20:30:03.772 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating ,delicious food is potato,time is 7
20:30:03.772 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating ,delicious food is potato,time is 8
20:30:03.773 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating ,delicious food is chicken,time is 9
20:30:03.773 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking ,this time food is rice,time is 10
20:30:03.773 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking ,this time food is beef,time is 11
20:30:03.773 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking ,this time food is chicken,time is 12
20:30:03.773 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking ,this time food is beef,time is 13
20:30:03.773 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking ,this time food is potato,time is 14
20:30:03.773 [pool-1-thread-1] DEBUG com.dz.demo.multiThread.LockSupportProducer - cooking over盘寡,time is 15
20:30:03.773 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating ,delicious food is rice,time is 10
20:30:03.773 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating ,delicious food is beef,time is 11
20:30:03.773 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating ,delicious food is chicken,time is 12
20:30:03.773 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating ,delicious food is beef,time is 13
20:30:03.773 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating ,delicious food is potato,time is 14
20:30:03.773 [pool-1-thread-2] DEBUG com.dz.demo.multiThread.LockSupportConsumer - eating over楚殿,time is 15
- 在分布式環(huán)境下的生產(chǎn)者消費(fèi)者模型問題需要借助消息隊(duì)列mq或者redis的list類型實(shí)現(xiàn)。這個(gè)后續(xù)文章講到mq與redis會分享相關(guān)實(shí)踐
本篇講到了常見的三種多線程協(xié)作的模型宴抚,主要講述了解決生產(chǎn)者消費(fèi)者模型的三種常用辦法勒魔,多線程協(xié)作的其他兩個(gè)模型和相關(guān)api的使用將在下一篇中進(jìn)行講解