生产者生产数据,消费者消费数据;
但是性能处理速度均有差异,因而需要一个中间队列协调;
3个厨师做甜点,有3个吃货来吃,如果厨师和吃货一对一,厨师的生产速度和吃货的吃饭速度均成成了短板,可能存在这样一种不协调的场景;
这个时候怎么办比较好呢?
加一个橱柜,糕点生产好一个一个放在橱柜里,吃货排队一个一个拿,这样是不是好多了呢,橱柜协调了厨师和吃货的关系,减少了浪费;
生产者 厨师
消费者 吃货
数据 糕点
中间队列 桌子
代码放在最后,先讲几个问题深入大家理解
面包被吃货吃光,等待厨师生产
面包被吃货吃光,等待厨师生产
面包被吃货吃光,等待厨师生产
厨师乙 在桌子上放入了 厨师乙产生的第1个面包
吃货甲 从桌子上取走了 厨师乙产生的第1个面包
面包被吃货吃光,等待厨师生产
面包被吃货吃光,等待厨师生产
厨师甲 在桌子上放入了 厨师甲产生的第2个面包
吃货丙 从桌子上取走了 厨师甲产生的第2个面包
面包被吃货吃光,等待厨师生产
厨师丙 在桌子上放入了 厨师丙产生的第3个面包
吃货乙 从桌子上取走了 厨师丙产生的第3个面包
面包被吃货吃光,等待厨师生产
厨师乙 在桌子上放入了 厨师乙产生的第4个面包
吃货甲 从桌子上取走了 厨师乙产生的第4个面包
面包被吃货吃光,等待厨师生产
厨师丙 在桌子上放入了 厨师丙产生的第5个面包
吃货丙 从桌子上取走了 厨师丙产生的第5个面包
面包被吃货吃光,等待厨师生产
面包被吃货吃光,等待厨师生产
厨师丙 在桌子上放入了 厨师丙产生的第18个面包
桌子放满了面包,不能再放了
桌子放满了面包,不能再放了
吃货丙 从桌子上取走了 厨师甲产生的第11个面包
厨师乙 在桌子上放入了 厨师乙产生的第7个面包
桌子放满了面包,不能再放了
桌子放满了面包,不能再放了
吃货乙 从桌子上取走了 厨师丙产生的第16个面包
厨师丙 在桌子上放入了 厨师丙产生的第19个面包
桌子放满了面包,不能再放了
吃货丙 从桌子上取走了 厨师丙产生的第18个面包
厨师甲 在桌子上放入了 厨师甲产生的第17个面包
桌子放满了面包,不能再放了
桌子放满了面包,不能再放了
桌子放满了面包,不能再放了
吃货乙 从桌子上取走了 厨师乙产生的第7个面包
厨师甲 在桌子上放入了 厨师甲产生的第22个面包
桌子放满了面包,不能再放了
桌子放满了面包,不能再放了
所以中间队列给我们提供了一个缓冲区,用于协调生产者和消费者间的性能差异,控制互斥
/**
* @author xuhe
* @description 生产者线程
* @date 2018/5/17
*/
public class ProducerThread extends Thread {
public static int index;
private String threadName;
private DataChannel dataChannel;
private Random random;
public ProducerThread(String threadName, DataChannel dataChannel, long randomSeed) {
this.threadName = threadName;
this.dataChannel = dataChannel;
this.random = new Random(randomSeed);
setName(threadName);
}
@Override
public void run() {
try {
while (true){
Thread.sleep(random.nextInt(500));
Data data= new Data();
data.setName(String.format("%s产生的第%s个面包",threadName,getIndex()));
dataChannel.put(data);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private synchronized int getIndex(){
return ++index;
}
}
package com.microparticletech.producer_consumer;
import java.util.Random;
/**
* @author xuhe
* @description 消费者线程
* @date 2018/5/17
*/
public class ConsumerThread extends Thread {
private DataChannel dataChannel;
private String threadName;
private Random random;
public ConsumerThread(String threadName,DataChannel dataChannel, long randomSeed) {
this.threadName = threadName;
this.dataChannel=dataChannel;
this.random = new Random(randomSeed);
setName(threadName);
}
@Override
public void run() {
System.out.println(threadName+"启动");
try {
while (true){
Data data=new Data();
data=dataChannel.get();
Thread.sleep(random.nextInt(1000));
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@lombok.Data
public class Data {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return
"name='" + name + '\'';
}
}
public interface DataChannel {
void put(Data data) throws InterruptedException;
Data get() throws InterruptedException;
}
public class DataChannelFIFOImpl implements DataChannel {
//先进先出的队列实现
private static final int CAPACITY=3;
private Data[] dataArray = new Data[CAPACITY];
private int head;
private int tail;
private int count;
@Override
public synchronized void put(Data data) throws InterruptedException {
while (count>=CAPACITY){
System.out.println("桌子放满了面包,不能再放了");
wait();
}
System.out.println(String.format("%s 在桌子上放入了 %s",Thread.currentThread().getName(),data.getName()));
dataArray[tail]=data;
tail=(tail+1)%CAPACITY;
count++;
notifyAll();
}
@Override
public synchronized Data get() throws InterruptedException {
while (count<=0){
System.out.println("面包被吃货吃光,等待厨师生产");
wait();
}
Data data=dataArray[head];
System.out.println(String.format("%s 从桌子上取走了 %s",Thread.currentThread().getName(),data.getName()));
count--;
head=(head+1)%CAPACITY;
notifyAll();
return data;
}
}
public class MainTest {
public static void main(String[] args) {
int size=3;
DataChannel channel = new DataChannelFIFOImpl();
Thread producer1 = new ProducerThread("厨师甲" , channel, 31415);
Thread producer2 = new ProducerThread("厨师乙" , channel, 92653);
Thread producer3 = new ProducerThread("厨师丙" , channel, 58979);
producer1.start();
producer2.start();
producer3.start();
Thread consumer1 = new ConsumerThread("吃货甲" , channel, 32384);
Thread consumer2 = new ConsumerThread("吃货乙" , channel, 62643);
Thread consumer3 = new ConsumerThread("吃货丙" , channel, 38327);
consumer1.start();
consumer2.start();
consumer3.start();
}
}