生产者消费者问题
- 单生产单消费问题:
- 将本例代码中生产者改为一个
- 将本例代码中消费者改为一个
- notifyAll()改为notify()也可正常工作
- 单生产多消费问题:
- 将本例代码中生产者改为一个
- 多生产单消费问题
- 将本例代码中消费者改为一个
- 多生产多消费问题
- 如本例所示
包子店
生产者消费者模式
- 多个生产者(2个):
- 包子店最多存放100个包子
- 包子超过80个时,生产者等待wait()
- 每当包子店包子少于80个时,会生产20个(一笼)包子,耗时3000ms;
- 生产者每次生产包子后,notifyAll()
- 多个消费者(10个):
- 每个消费者每隔一定时间(0~500ms)
- 消费随机数目(1-5)的包子
- 包子铺包子不够时,消费者等待wait()
- 消费者每次消费包子后,notifyAll()
类图
包子类、包子铺类
消费者、生产者
客户端
代码
包子类
public class StuffedBun {
}
包子铺类
public class BunShop {
//最多有100个包子
List<StuffedBun> list;
public BunShop() {
this.list = new ArrayList<>(100);
}
//生产者:包子数小于80,每3000ms生产20个包子
public synchronized void producer() {
while (true) {
while (list.size() >= 80) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 0; i < 20; i++) {
list.add(new StuffedBun());
}
System.out.printf("生产者%s生产了一批包子,目前包子店还剩%d个包子\n", Thread.currentThread().getName(), list.size());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.notifyAll();
}
}
//消费者 每隔0~500ms 随机消费1-5个包子
public synchronized void consumer() {
while (true) {
Random random = new Random();
int num = random.nextInt(5) + 1;
int seconds = random.nextInt(500) + 1;
try {
Thread.sleep(seconds);
System.out.printf("消费者%s在%d毫秒后又来消费了\n", Thread.currentThread().getName(), seconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (list.size() < num) {
try {
System.out.printf("目前包子店只有%d个包子,%s需要%d个包子;等待包子中\n", list.size(), Thread.currentThread().getName(), num);
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
for (int i = 0; i < num; i++) {
list.remove(list.size() - 1);
}
//消费完 可能就缺包子了
System.out.printf("消费者%s消费了%d个包子;目前包子店还剩%d个包子\n", Thread.currentThread().getName(), num, list.size());
this.notifyAll();
}
}
}
生产者
public class Producer extends Thread {
BunShop bunShop;
public Producer(BunShop bunShop, String name) {
this.bunShop = bunShop;
this.setName(name);
}
@Override
public void run() {
bunShop.producer();
}
}
消费者
public class Consumer extends Thread {
BunShop bunShop ;
public Consumer(BunShop bunShop,String name) {
this.bunShop = bunShop;
this.setName(name);
}
@Override
public void run() {
bunShop.consumer( );
}
}
客户端
public class Client {
public static void main(String[] args) {
BunShop bunShop = new BunShop();//创建一个最多容纳100包子的 包子铺
//10个消费者线程
for (int i = 1; i <= 10; i++) {
new Consumer(bunShop, "consumer" + i).start();
}
//2个生产者线程
for (int i = 1; i <= 2; i++) {
new Producer(bunShop, "product" + i).start();
}
}
}
运行效果
/*
消费者consumer10在307毫秒后又来消费了
目前包子店只有0个包子,consumer10需要2个包子;等待包子中
消费者consumer9在358毫秒后又来消费了
目前包子店只有0个包子,consumer9需要4个包子;等待包子中
消费者consumer8在483毫秒后又来消费了
目前包子店只有0个包子,consumer8需要1个包子;等待包子中
生产者product2生产了一批包子,目前包子店还剩20个包子
生产者product2生产了一批包子,目前包子店还剩40个包子
生产者product2生产了一批包子,目前包子店还剩60个包子
生产者product2生产了一批包子,目前包子店还剩80个包子
...
目前包子店只有0个包子,consumer3需要5个包子;等待包子中
消费者consumer2在95毫秒后又来消费了
目前包子店只有0个包子,consumer2需要5个包子;等待包子中
目前包子店只有0个包子,consumer7需要5个包子;等待包子中
生产者product1生产了一批包子,目前包子店还剩20个包子
生产者product1生产了一批包子,目前包子店还剩40个包子
*/
部分笔试题实例
该部分面试题/笔试题实例来自 @ 几到多线程笔试题,有时间练练。
第六题:
生产者消费者问题:
这是一个非常经典的多线程题目,题目大意如下:有一个生产者在生产产品,这些产品将提供给若干个消费者去消费,为了使生产者和消费者能并发执行,在两者之间设置一个有多个缓冲区的缓冲池,生产者将它生产的产品放入一个缓冲区中,消费者可以从缓冲区中取走产品进行消费,所有生产者和消费者都是异步方式运行的,但它们必须保持同步,即不允许消费者到一个空的缓冲区中取产品,也不允许生产者向一个已经装满产品且尚未被取走的缓冲区中投放产品。
问题3-5解法见前一篇文章
问题7解法见后一篇文章