生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题,常用的方法有信号灯法等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。
情形一:简单模型,生产者产生一个,消费者拿一个。
class Q{
private int n;
private boolean valueSet=false;
public Q(int n){
this.n=n;
}
public Q(){}
public synchronized void add() throws InterruptedException {
if(valueSet){
wait();
}
valueSet=true;
n++;
System.out.println("have:"+n +" "+"增加一个");
notify();
}
public synchronized int move() throws InterruptedException {
if(!valueSet){
wait();
}
n--;
System.out.println("have:"+n+" "+"减少一个");
valueSet=false;
notify();
return this.n;
}
}
public class Customer implements Runnable{
Q q;
public Customer(Q q){
this.q=q;
new Thread(this,"Customer").start();
}
@Override
public void run() {
while(true){
try {
q.move();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class Product implements Runnable{
Q q;
public Product(Q q){
this.q=q;
new Thread(this,"Product").start();
}
@Override
public void run() {
int i=0;
while (true){
try {
q.add();
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
public static void main(String[] args) throws InterruptedException {
Q q=new Q(1);
Product p=new Product(q);
Customer c=new Customer(q);
}
输出:
have:2 增加一个
have:1 减少一个
have:2 增加一个
have:1 减少一个
have:2 增加一个
have:1 减少一个
have:2 增加一个
have:1 减少一个
have:2 增加一个
have:1 减少一个
have:2 增加一个
have:1 减少一个
have:2 增加一个
have:1 减少一个
have:2 增加一个
have:1 减少一个
have:2 增加一个
have:1 减少一个
have:2 增加一个
have:1 减少一个
have:2 增加一个
have:1 减少一个
have:2 增加一个
have:1 减少一个
情形二:多个消费者多个生产者
import java.util.List;
public class CustomerPlus implements Runnable{
private List<Integer>list;
public CustomerPlus(){};
public CustomerPlus(List<Integer>list){
this.list=list;
}
@Override
public void run() {
while (true) {
synchronized (list) {
int n=list.size();
if (n > 0) {
list.remove(n-1);
System.out.println("消费一个 "+"当前数量为:"+list.size());
}
list.notifyAll();
try {
Thread.sleep(100);
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
class ProductPlus implements Runnable{
private List<Integer>list;
public ProductPlus(){}
public ProductPlus(List<Integer>list){
this.list=list;
}
@Override
public void run() {
while (true) {
synchronized (list) {
if (list.size() < 20) {
list.add(1);
System.out.println("生产一个 "+"当前数量为:"+list.size());
}
list.notifyAll();
try {
Thread.sleep(100);
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
public static void main(String[] args) throws InterruptedException {
List<Integer>list=new ArrayList<>(20);
list.add(1);
list.add(1);
ProductPlus p1=new ProductPlus(list);
ProductPlus p2=new ProductPlus(list);
ProductPlus p3=new ProductPlus(list);
CustomerPlus c1=new CustomerPlus(list);
CustomerPlus c2=new CustomerPlus(list);
Thread t1=new Thread(p1);
t1.start();
Thread.sleep(100);
Thread t2=new Thread(p2);
t2.start();
Thread.sleep(100);
Thread t3=new Thread(p3);
t3.start();
Thread.sleep(100);
Thread t4=new Thread(c1);
t4.start();
Thread.sleep(100);
Thread t5=new Thread(c2);
t5.start();
Thread.sleep(100);
}
运行结果:
生产一个 当前数量为:3
生产一个 当前数量为:4
生产一个 当前数量为:5
生产一个 当前数量为:6
生产一个 当前数量为:7
消费一个 当前数量为:6
生产一个 当前数量为:7
生产一个 当前数量为:8
消费一个 当前数量为:7
生产一个 当前数量为:8
生产一个 当前数量为:9
生产一个 当前数量为:10
消费一个 当前数量为:9
生产一个 当前数量为:10
生产一个 当前数量为:11
消费一个 当前数量为:10
生产一个 当前数量为:11
消费一个 当前数量为:10
生产一个 当前数量为:11
生产一个 当前数量为:12
消费一个 当前数量为:11
生产一个 当前数量为:12
生产一个 当前数量为:13
生产一个 当前数量为:14
消费一个 当前数量为:13
生产一个 当前数量为:14
生产一个 当前数量为:15
消费一个 当前数量为:14
生产一个 当前数量为:15
消费一个 当前数量为:14
生产一个 当前数量为:15
生产一个 当前数量为:16
消费一个 当前数量为:15
生产一个 当前数量为:16
生产一个 当前数量为:17
生产一个 当前数量为:18
消费一个 当前数量为:17
生产一个 当前数量为:18
生产一个 当前数量为:19
消费一个 当前数量为:18
生产一个 当前数量为:19
消费一个 当前数量为:18
生产一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
消费一个 当前数量为:18
生产一个 当前数量为:19
消费一个 当前数量为:18
生产一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
消费一个 当前数量为:18
生产一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
消费一个 当前数量为:18
生产一个 当前数量为:19
消费一个 当前数量为:18
生产一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
消费一个 当前数量为:18
生产一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
消费一个 当前数量为:18
生产一个 当前数量为:19
消费一个 当前数量为:18
生产一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
生产一个 当前数量为:20
消费一个 当前数量为:19
消费一个 当前数量为:18
生产一个 当前数量为:19
生产一个 当前数量为:20