版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lin1094201572/article/details/82388999
*前言
生产者消费者问题是java多线程中五个同步问题的经典模型之。
问题描述:
生产者生产产品,消费者消费产品,可以有一个或多个生产者生产产品供一个或多个消费者消费产品。
为使生产与消费并发,在生产者和消费者之间建立共享的缓冲区,生产者生产的产品放入缓冲区,消费者从缓冲区中消费产品。
生产者与消费者需保持同步,生产者不能在缓冲区已满时继续生产,消费者不能在缓冲区为空时消费产品。
解决方案:
1)缓冲区数据结构使用栈,生产者生产产品进栈,消费者消费产品出栈,该缓冲区栈作为多个线程共享资源。
2)多个生产和消费线程可以并发访问缓冲区,需要互斥锁来控制对缓冲区的操作。使用synchronized关键字修饰对缓冲区的操作方法,当执行被关键字修饰的方法的过程中会锁住当前缓冲区,即将缓冲区栈加上了互斥锁。
3)缓冲区栈中空时,消费线程进入阻塞状态,而生产线程需要为就绪状态,缓冲区栈中满时,生产线程进入阻塞状态,而消费线程需要为就绪状态。使用父类Object类的 wait() 方法,使拿住互斥锁的线程进入缓冲区栈对象中的 wait pool,同时确保其他所有生产线程就绪,使用 notifyAll() 方法叫醒其他所有线程。
代码实现:
产品类
class Item{
int id;
String name;
Item(int id){
this.id = id;
}
public String toString() {
return "Item{id:"+id+"}";
}
}
缓冲区栈类
class SynchronizedStack{
// 记录存放数量
int size = 0;
// 初始化数组大小,即存储最大容量
private Item[] items = new Item[6];
// 进栈
synchronized void push(Item item) {
//若数组大小和存储数量相等,即存储已满
while(items.length==size) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 叫醒其他所有线程等待拿锁,即叫醒该对象wait pool中所有线程
this.notifyAll();
items[size] = item;
size++;
}
// 出栈
synchronized Item pop() {
while(size==0) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 叫醒其他所有线程
this.notifyAll();
size--;
return items[size];
}
}
生产者类
class Producer implements Runnable{
SynchronizedStack stack = null;
Producer(SynchronizedStack stack){
this.stack = stack;
}
@Override
public void run() {
for(int i=0; i<20; i++) {
Item item = new Item(i);
stack.push(item);
System.out.println(Thread.currentThread().getName()+"-生产了-"+item);
// 线程的sleep会一直贪婪的拿着锁,而wait会释放锁
try {
Thread.sleep((long) (Math.random()*500));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
消费者
class Consumer implements Runnable{
SynchronizedStack stack = null;
Consumer(SynchronizedStack stack){
this.stack = stack;
}
@Override
public void run() {
for(int i=0; i<10; i++) {
Item item = stack.pop();
System.out.println(Thread.currentThread().getName()+"-消费了-"+item);
try {
Thread.sleep((long) (Math.random()*500));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
问题模拟主线程类
public class ProducerConsumer {
public static void main(String[] args) {
// 缓冲区栈
SynchronizedStack syncStack = new SynchronizedStack();
// 生产者
Producer producer = new Producer(syncStack);
// 消费者
Consumer consumer = new Consumer(syncStack);
// 生产线程
Thread producerThread = new Thread(producer,"producer");
// 消费线程1
Thread consumerThread1 = new Thread(consumer,"consumer1");
// 消费线程2
Thread consumerThread2 = new Thread(consumer,"consumer2");
// 启动所有线程
producerThread.start();
consumerThread1.start();
consumerThread2.start();
}
}
这里简单模拟了一个生产者生产20个产品,两个消费者各消费10个产品。若生产者生产总数过少,所有消费线程会一直wait等待。若生产者生产过多,多于栈的存储空间,生产线程一直出去阻塞状态,少于则线程结束。