目录
前言
之前学习多线程所执行的代码我们可以看到他们的执行都是随机的,哪个电影院窗口卖出一张门票是不固定的,但是如果我们想要让线程执行的顺序固定,应该如何操作呢?
一、什么是"生产者-消费者"模型?
为了方便理解,我们打个最通俗的比方:包子铺。
-
生产者**(Producer)**:后厨做包子的师傅。
-
消费者**(Consumer)**:在前台买包子的顾客。
-
缓冲区**(Buffer)**:装包子的蒸笼(容量有限,比如最多装 10 个)。
如果没有蒸笼,师傅做好一个包子,必须亲手交到顾客手里才能回去做下一个。如果顾客还没来,师傅就只能傻等着;反过来,如果师傅做得慢,顾客也得干等着。
1.经典实现(wait()、notifyAll())
桌子:定义了锁、消费者可以消费的总数、判断桌子上是否有包子。
java
public class Desk {
//锁
public static Object obj = new Object();
//总数
public static int count = 10;
//flag判空
public static int flag = 0;
}
消费者线程:
java
//消费者线程
public class Consumer extends Thread{
@Override
public void run() {
while(true){
synchronized (Desk.obj){
if(Desk.count == 0){ //1.消费者吃饱了
break;
} else { //2.消费者没吃饱
if(Desk.flag == 0){ //2.1桌子上没食物
try {
Desk.obj.wait(); //2.1.1等待
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} else { //2.2桌子上有食物
Desk.count--; //2.2.1开吃
Desk.flag = 0;
System.out.println(getName() + "正在吃东西,还能再吃" + Desk.count + "份食物");
Desk.obj.notifyAll(); //2.2.2叫醒生产者.
}
}
}
}
}
}
生产者线程:
java
//生产者线程
public class Productor extends Thread{
@Override
public void run() {
while(true){
synchronized (Desk.obj){
if(Desk.count == 0){ //1.消费者吃饱了,就不用做了
break;
} else { //2.消费者没吃饱
if(Desk.flag == 1){ //2.1桌子上是有食物的
try {
Desk.obj.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
} else{ //2.2桌子上没食物
Desk.flag = 1; //2.2.1做食物
System.out.println(getName() + "正在做食物");
Desk.obj.notifyAll();
}
}
}
}
}
}
测试:
java
public class Test {
public static void main(String[] args) {
Consumer c = new Consumer();
Productor p = new Productor();
c.setName("消费者");
p.setName("生产者");
c.start();
p.start();
}
}
运行结果:

2.阻塞队列实现(BlockingQueue)

①阻塞队列的继承结构
接口:Itreable、Collection、Queue、BlockingQueue
实现类:
- ArrayBlockingQueue:底层是数组,有界。
- LinkedBlockingQueue:底层是链表,无界,但不是真正的无界,最大为int的最大值。
消费者线程:
java
public class Consumer extends Thread{
ArrayBlockingQueue<String> queue;
public Consumer(ArrayBlockingQueue<String> queue) {
this.queue = queue;
}
@Override
public void run() {
while(true){
try {
String take = queue.take();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
}
生产者线程:
java
public class Productor extends Thread{
ArrayBlockingQueue<String> queue;
public Productor(ArrayBlockingQueue<String> queue) {
this.queue = queue;
}
@Override
public void run() {
try {
queue.put("包子");
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
测试:
java
public class Test {
public static void main(String[] args) {
//定义阻塞队列
ArrayBlockingQueue<String> abq = new ArrayBlockingQueue<>(1);
Consumer c = new Consumer(abq);
Productor p = new Productor(abq);
c.start();
p.start();
}
}
总结
生产者-消费者模型并不是一个具体的类,而是一种极具智慧的架构思想。
-
解耦:生产者和消费者彼此不直接打交道,只和缓冲区交互。
-
异步:大家各干各的,互不干扰。
-
缓冲:完美解决生产和消费速度不匹配的问题。
😁😁