生产者消费者模型具体来讲,就是在一个系统中,存在生产者和消费者两种角色和一个内存缓冲区。
一个或者多个生产者 产生商品(数据) 并将商品存放到仓库中(内存缓冲区);
一个或者多个消费者 消费商品(数据)并将商品从仓库中取出(内存缓冲区);
仓库有存取功能,并且当仓库存满数据时,只取不存;当仓库没有商品时,只存不取。
- 生产者持续生产,直到缓冲区满,阻塞;缓冲区不满后,继续生产
- 消费者持续消费,直到缓冲区空,阻塞;缓冲区不空后,继续消费
- 生产者可以有多个,消费者也可以有多个
模型一
使用 wait() 、 notifyAll()来进行阻塞和唤醒线程,使用ArrayList 从当缓冲区。
定义一个缓存队列
/**
* Created By : fumm
* DATE : 2019/7/11 16:13
* Describe : 公共队列
* 生产者/消费者设计模式顾名思义就是两个互斥线程,一个负责生产,一个负责消费,两者是线程不安全的;
* 为了保证互斥线程的安全性,需要做对应的处理,以上代码使用了synchronized 、wait()、notifyAll()来保证。
**/
public class PublicQueue<T> {
private int MAX_NUM = 50;
private List<T> mQ = new ArrayList<>();
private LinkedHashMap<Integer, T> linkedHashMap = new LinkedHashMap<>();//缓冲区
public synchronized void add(T t) {
// 不安全 (如果线程运行至此处刚好切换到其他线程 操作mQ ,mQ.size可能会变化)
// int size = mQ.size();
if (mQ.size()<= MAX_NUM) {
// 仓库未满 添加
mQ.add(t);
System.out.println("生产者生产 :" + t.toString());
notifyAll();
} else {
try {
System.out.println("生产者 :等待");
// 仓库已满 当前线程等待
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public synchronized void remove() {
// int size = mQ.size();
if (mQ.size() <= 0) {
// 当前线程等待
try {
System.out.println("消费者 :等待");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
T t = mQ.remove(size - 1);
System.out.println("消费者消费 :" + t.toString());
notifyAll();
}
}
}
定义一个生产者
/**
* Created By : fumm
* DATE : 2019/7/11 16:23
* Describe : 生产者线程
**/
public class ProduceThread extends Thread {
private PublicQueue mQueue;
public ProduceThread(PublicQueue mQueue) {
this.mQueue = mQueue;
}
@Override
public void run() {
super.run();
for (int i = 0; i < 100000; i++) {
mQueue.add("i =" + i);
}
}
}
定义一个消费者
/**
* Created By : fumm
* DATE : 2019/7/11 16:23
* Describe : 消费者线程
**/
public class ConsumerThread extends Thread {
private PublicQueue mQueue;
public ConsumerThread(PublicQueue mQueue) {
this.mQueue = mQueue;
}
@Override
public void run() {
super.run();
while (true) {
mQueue.remove();
}
}
}
模型二
使用 ReentrantLock.lock() Condition.await()[等待] Condition.signalAll() [唤醒]、,使用ArrayList 从当缓冲区。
/**
* Created By : fumm
* DATE : 2019/7/11 17:04
* Describe : 生产者 消费者 模型2
* 定义一个缓存队列
**/
public class PublicQueue2<T> {
private List<T> mQ = new ArrayList<>();
// private LinkedHashMap<Integer, T> mQ = new LinkedHashMap<>();//缓冲区
private int MAX_NUM = 50;
private int putIndex = 0;//数据插入的角标
private final Condition mAddCondition;
private final Condition mRemoveCondition;
private final ReentrantLock mLock;
public PublicQueue2() {
mLock = new ReentrantLock();
mAddCondition = mLock.newCondition();
mRemoveCondition = mLock.newCondition();
}
public void add(T t) {
try {
mLock.lock();
if (mQ.size() == MAX_NUM) {
System.out.println("生产者 :等待" + "----size:" + mQ.size());
// 生产者阻塞等待
mAddCondition.await();
}
mQ.add(t);
// mQ.put(putIndex, t);
System.out.println("生产者生产 :" + t.toString());
putIndex = (putIndex + 1 >= MAX_NUM) ? (putIndex + 1) % MAX_NUM : putIndex + 1;
// 唤醒消费者
mRemoveCondition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
mLock.unlock();
}
}
public void remove() {
T t = null;
try {
mLock.lock();
if (mQ.size() == 0) {
System.out.println("消费者 :等待" + "----size:" + mQ.size());
// 消费者等待 阻塞
mRemoveCondition.await();
}
// Iterator it = mQ.entrySet().iterator();
// if (it.hasNext()) {
// Map.Entry<Integer, T> entry = (Map.Entry<Integer, T>) it.next();
// t = entry.getValue();
// int index = entry.getKey();
// mQ.remove(index);
// System.out.println("消费者消费 :" + t.toString());
// }
mQ.remove(mQ.size() - 1);
mAddCondition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
mLock.unlock();
}
}
// 定义一个生产者
public static class ProduceThread extends Thread {
private PublicQueue2 mQ;
public ProduceThread(PublicQueue2 mQ) {
this.mQ = mQ;
}
@Override
public void run() {
super.run();
for (int i = 0; i < 1000; i++) {
mQ.add("--i= " + i);
}
}
}
// 定义一个消费者
public static class ConsumerThread extends Thread {
private PublicQueue2 mQ;
public ConsumerThread(PublicQueue2 mQ) {
this.mQ = mQ;
}
@Override
public void run() {
super.run();
while (true) {
mQ.remove();
}
}
}
}
模型三
使用 BlockingDeque.put(t) 和 BlockingDeque.take(),使用ArrayList 从当缓冲区。
/**
* Created By : fumm
* DATE : 2019/7/12 9:07
* Describe : TODO
**/
public class PublicQueue4<T> {
private static final int MAX_NUM = 5;
private BlockingDeque<T> blockingDeque = new LinkedBlockingDeque<>(MAX_NUM);//缓冲区
public void add(T t) {
// blockingDeque.add(t);
try {
Thread.sleep((long) (Math.random() * 300));
blockingDeque.put(t);
System.out.println("生产一个产品:" + t.toString() + "---剩余空间:" + (MAX_NUM - blockingDeque.size()));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void remove() {
// blockingDeque.remove();
try {
System.out.println("仓库产品数量:" + blockingDeque.size());
T t = blockingDeque.take();
System.out.println("消费一个产品:" + t.toString() + "---剩余产品:" + blockingDeque.size());
Thread.sleep(200 + (long) (Math.random() * 100));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public static class ProduceThread extends Thread {
private PublicQueue4 mQueue4;
public ProduceThread(PublicQueue4 queue4) {
this.mQueue4 = queue4;
}
@Override
public void run() {
super.run();
for (int i = 0; i < 100; i++) {
mQueue4.add("i--->" + i);
}
}
}
public static class ConsumerThread extends Thread {
private PublicQueue4 mQueue4;
public ConsumerThread(PublicQueue4 mQueue4) {
this.mQueue4 = mQueue4;
}
@Override
public void run() {
super.run();
while (true){
mQueue4.remove();
}
}
}
}
测试类
/**
* Created By : fumm
* DATE : 2019/7/11 15:50
* Describe : 测试生产者 和消费者模型
* 1、生产者生产数据到缓冲区中,消费者从缓冲区中取数据。
* 2、如果缓冲区已经满了,则生产者线程阻塞;
* 3、如果缓冲区为空,那么消费者线程阻塞。
**/
public class Test {
public static void main(String[] args) {
PublicQueue<String> queue = new PublicQueue<>();
// 生产者 消费者 模型一
// ProduceThread produceThread = new ProduceThread(queue);
// ConsumerThread consumerThread = new ConsumerThread(queue);
// produceThread.start();
// consumerThread.start();
// 生产者 消费者 模型二
// PublicQueue2<String> queue2 = new PublicQueue2<>();
// PublicQueue2.ProduceThread produceThread = new PublicQueue2.ProduceThread(queue2);
// PublicQueue2.ConsumerThread consumerThread = new PublicQueue2.ConsumerThread(queue2);
// produceThread.start();
// consumerThread.start();
// 生产者 消费者 模型二
PublicQueue3<String> queue3 = new PublicQueue3<>();
PublicQueue3.ProduceThread produceThread = new PublicQueue3.ProduceThread(queue3);
PublicQueue3.ConsumerThread consumerThread = new PublicQueue3.ConsumerThread(queue3);
produceThread.start();
consumerThread.start();
// 生产者 消费者 模型四
// PublicQueue4<String> queue4 = new PublicQueue4<>();
// PublicQueue4.ConsumerThread c1 = new PublicQueue4.ConsumerThread(queue4);
// PublicQueue4.ProduceThread p1= new PublicQueue4.ProduceThread(queue4);
// c1.start();
// p1.start();
}
}
博客介绍了生产者消费者模型,即系统中有生产者、消费者和内存缓冲区,生产者存数据,消费者取数据,仓库有存取规则。还给出三种Java实现模型,分别用wait()、notifyAll(),ReentrantLock和Condition,以及BlockingDeque的方法,均用ArrayList作缓冲区。
11万+

被折叠的 条评论
为什么被折叠?



