1. 引言
在上一篇博客中,我们介绍了第四种线程之间的通信方式:等待通知机制。等待通知机制最典型的例子:消费者/生产者模式。在此篇博客中主要介绍等待通知机制中的:消费者/生产者模式,
什么是消费者/生产者模式?假设我们要生产一种产品,我们一类线程用于生产产品,另外一类线程用于消费产品。在这个Demo中需要三种类:
- 产品(这里我们用array数组代替)
- 生产者
- 消费者
在消费者/生产者模式中过程介绍
- 在生产者/消费者模式中,产品的数量为1 (注意产品的数量要么等于0,要么等于1)
- 对于生产者来说:如果产品的数量为0,那么生产者应该生产产品,并且生产者通知消费者,让消费者消费。如果产品数量等于1,那么生产者应该等待消费者消费,如果消费者不消费,生产者将一直等待下去
- 对于消费者来说:如果产品的数量等于0,那么消费者应该等待生产者生产,如果产品的数量等译1,那么消费者进行消费,消费完成后应该通知生产者生产商品
消费者/生产者模式一共分为以下几种情况:一生产一消费,一生产多消费,多生产一消费,多生产多消费
2. 一生产一消费情况
2.1 生产者(Producer
)
import java.util.List;
//生产者
public class Producer {
// arr是我们的产品
private List arr;
// 用于控制等待通知机制的对象锁
private Object lock;
public Producer(List arr, Object lock) {
this.arr = arr;
this.lock = lock;
}
// 用户生产产品的方法
public void addProduct() throws Exception {
synchronized (lock) {
if (arr.size() > 0) {
System.out.println("已经拥有了一个产品,陷入等待");
lock.wait();
}
System.out.println("我要生产产品了");
arr.add("牛奶");
lock.notify();
}
}
}
2.2 消费者(Customer
)
import java.util.List;
public class Customer {
// arr是我们的产品
private List arr;
// 用于控制等待通知机制的对象锁
private Object lock;
public Customer(List arr, Object lock) {
this.arr = arr;
this.lock = lock;
}
// 用于消费的方法
public void csmProduct() throws Exception {
synchronized (lock) {
if (arr.size() == 0) {
System.out.println("没有产品,等待中");
lock.wait();
}
System.out.println("消费产品" + arr.get(0));
arr.remove(0);
// 通知生产者生产
lock.notify();
}
}
}
2.3 main函数
import java.util.ArrayList;
import java.util.List;
public class app {
public static void main(String[] args) {
// 创建我们的产品
List arr = new ArrayList();
// 创建我们的锁
Object lock = new Object();
// 创建消费者
final Customer c = new Customer(arr, lock);
// 创建生产者
final Producer p = new Producer(arr, lock);
// 消费者线程
Runnable ct = new Runnable() {
public void run() {
try {
while (true) {
c.csmProduct();
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
// 生产者线程
Runnable pt = new Runnable() {
public void run() {
try {
while (true) {
p.addProduct();
}
} catch (Exception e) {
e.printStackTrace();
}
}
};
// 创建一个生产者
new Thread(pt).start();
// 创建一个消费者
new Thread(ct).start();
}
}
2.4 运行结果
- 从上面例子可以看出来,我们通过等待通知机制成功实现了一生产一消费的生产者消费模式
- 注意:线程ct和现成pt都需要获得
lock
对象锁 - 注意:一生产一消费代码是可以这样写的,在多生产多消费的代码中就要修改了。
3.一生产多消费
3.1 生产者(Producer
)(代码不变)
3.2 消费者(Customer
)
import java.util.List;
public class Customer {
// arr是我们的产品
private List arr;
// 用于控制等待通知机制的对象锁
private Object lock;
public Customer(List arr, Object lock) {
this.arr = arr;
this.lock = lock;
}
// 用于消费的方法
public void csmProduct() throws Exception {
synchronized (lock) {
while (arr.size() == 0) {
System.out.println("没有产品,等待中");
lock.wait();
}
System.out.println("消费产品" + arr.get(0));
arr.remove(0);
// 通知生产者生产(注意这里代码修改了)
lock.notifyAll();
}
}
}
- 注意代码修改的两个地方:
- 一个是判断产品的数量,由以前的
if
改为了while
- 一个是唤醒线程由:由
notify()
改为了notifyAll()
3.3main方法
//...上面代码和一生产一消费一样
// 创建一个生产者
new Thread(pt).start();
// 创建三个消费者
new Thread(ct).start();
new Thread(ct).start();
new Thread(ct).start();
3.4 运行结果
3.5 修改代码的原因
4 多生产一消费
4.1 生产者代码(修改两处)
import java.util.List;
//生产者
public class Producer {
// arr是我们的产品
private List arr;
// 用于控制等待通知机制的对象锁
private Object lock;
public Producer(List arr, Object lock) {
this.arr = arr;
this.lock = lock;
}
// 用户生产产品的方法
public void addProduct() throws Exception {
synchronized (lock) {
//修改的第一处
while (arr.size() > 0) {
System.out.println("已经拥有了一个产品,陷入等待");
lock.wait();
}
System.out.println("我要生产产品了");
arr.add("牛奶");
//修改的第二处
lock.notifyAll();
}
}
}
- 原理和一生产多消费的原理一样,参考上面的原理图
4.2 消费者代码(和一生产一消费的消费者代码一样)
4.3main函数代码
//......上面的代码和一生产一消费的代码一样
// 创建三个生产者
new Thread(pt).start();
new Thread(pt).start();
new Thread(pt).start();
// 创建一个消费者
new Thread(ct).start();
5.多生产/多消费
5.1生产者代码(和多生产一消费代码一样)
5.2消费者代码(和一生产多消费代码一样)
5.3main代码
//.....上面代码和一生产一消费一样
// 创建三个生产者
new Thread(pt).start();
new Thread(pt).start();
new Thread(pt).start();
// 创建三个消费者
new Thread(ct).start();
new Thread(ct).start();
new Thread(ct).start();
5.4 多生产多消费代码的缺陷
6. 总结
在本篇博客中,主要利用等待通知机制实现了消费者生产者模式,其中包括有一生产一消费,多生产一消费,一消费多生产,多生产多消费等情况。注意:上面的例子,产品的数量最多是1。还有注意本篇博客,多生产多消费中代码的缺陷。