一.生产者消费者模型的概念
生产者消费者模型是多线程并发编程中的一种重要模式,用于解决生产者和消费者之间的协作问题。在这个模型中,生产者负责生成数据或者任务,然后将其交给消费者来处理,而消费者则负责处理这些数据或者任务。
具体来说,生产者消费者模型通常涉及到一个共享的数据缓冲区(也称为队列),生产者向其中放入数据,而消费者从中取出数据进行处理。以下是该模型的基本概念:
-
生产者:负责生成数据或任务,并将其放入共享的数据缓冲区中。生产者的速度可能快于或者慢于消费者。
-
消费者:负责从共享的数据缓冲区中取出数据或任务,并进行处理。消费者可能以不同的速度处理数据,有些可能快速处理,有些可能慢速处理。
-
共享的数据缓冲区:生产者和消费者之间共享的数据存储区域。它可以是一个队列、缓冲区或者其他形式的数据结构。
-
协调机制:生产者和消费者之间需要一种机制来协调彼此的行为,例如当数据缓冲区为空时,消费者需要等待;当数据缓冲区满时,生产者需要等待。
二.生产者消费者模型的实现
1)阻塞队列
阻塞队列(Blocking Queue)是一种特殊类型的队列,它支持在队列为空时进行获取元素的线程阻塞等待,或者在队列已满时进行插入元素的线程阻塞等待。阻塞队列常用于生产者消费者模型中,可以帮助实现生产者和消费者之间的协调与同步。
代码实现:
public class BlockingQueue {
//阻塞队列的长度
private volatile int size;
//存放数据的数组
private int[] items=new int[1000];
//队头
private int head;
//队尾
private int tail;
//put()方法放置生产者生产的元素
public void put(int value) throws InterruptedException {
//同一时间只能有一个线程放置,所以加锁
synchronized (this){
//如果队列满了,使当前线程等待,直到消费者消费元素后唤醒
//建议为while而不是if, 否则 notifyAll 的时候, 该线程从 wait 中被唤醒
//但是紧接着并未抢占到锁. 当锁被抢占的时候, 可能又已经队列满了
//就只能继续等待
while (size==items.length){
wait();
}
//队列添加元素
items[head]=value;
head=(head+1)%items.length;
size++;
//添加后唤醒等待的线程
notifyAll();
}
}
//take()方法消耗消费者消费的元素
public int take() throws InterruptedException {
//用value存放要消耗的元素
int value=0;
synchronized (this){
//如果队列为空,使当前线程等待,直到生产者消生产元素后唤醒
while (size==0){
wait();
}
//消耗元素
value=items[tail];
tail=(tail+1)%items.length;
size--;
//消费后唤醒等待的线程
notifyAll();
}
return value;
}
//返回队列的长度
public synchronized int size(){
return size;
}
}
2)模型实现
有了阻塞队列后,我们就可以简单的实现一个生产者消费者模型了
代码如下:
import java.util.Random;
public class Producer_Consumer {
public static void main(String[] args) throws InterruptedException {
//阻塞队列
BlockingQueue blockingQueue=new BlockingQueue();
//消费者线程
Thread consumer=new Thread(()->{
while (true){
try {
//消费元素
System.out.println(blockingQueue.take());
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
//生产者线程
Thread producer=new Thread(()->{
Random random=new Random();
while (true){
try {
//生产元素
blockingQueue.put(random.nextInt(10000));
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
//启动线程
consumer.start();
producer.start();
//等待线程执行完毕
consumer.join();
producer.join();
//任务完成后的最后收尾
System.out.println("生产者消费者执行完成");
}
}
(代码实现时使用了lambda表达式,如对lambda不熟悉,可以参考lambda表达式-CSDN博客)
到这里,一个生产者消费者模型的简单流程和实现就介绍完了~