生产者消费者问题,是一个多线程同步问题的经典案例。该问题描述了两个共享固定大小缓冲区的线程--即所谓的“生产者”和“消费者”在实际运行时会发生的问题。。生产者主要的作用是生产一定量的数据放置到缓冲区,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。
该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区空时消耗数据。
话不多说,直接上代码
/**
* 馒头对象
* @author Quan
*
*/
public class Cake {
private int id;
public Cake(int id) {
this.id = id;
}
@Override
public String toString() {
return " " + id + " Cake";
}
}
/**
* 容器对象 用来放馒头
* @author Quan
*
*/
public class Frame {
private volatile int count = 0; //设置容器的大小,最大只能装10个馒头
public synchronized void push(Cake cake){ //放入馒头
try {
while(count>10){ //如果大于容器的数量,就进行等待
wait();
}
count ++;
System.out.println("做第" + cake.toString());
notify(); //通知消费者取馒头
} catch (Exception e) {
System.out.println("push error");
}
}
public synchronized void pop(Cake cake){ //取馒头
try {
while(count == 0){ //如果馒头数量为0,就进行等待
wait();
}
count --;
System.out.println("吃第" + cake.toString());
notify(); //通知生产者做馒头
} catch (Exception e) {
System.out.println("pop error");
}
}
public void count(){
System.out.println("当前剩余" + count + "个馒头");
}
}
生产者和消费者都要持有一个容器对象,以对容器中的对象也就是馒头数量进行操作
/**
* 生产者
* @author Quan
*
*/
public class Producer implements Runnable{
private Frame frame; //持有容器对象
private int total;
public Producer(Frame frame,int i) {
this.frame = frame;
this.total = i;
}
@Override
public void run() {
try {
for (int i = 0; i < total; i++) { //做10个馒头
Cake cake = new Cake(i);
frame.push(cake);
Thread.sleep(100); //每做一个馒头休眠100毫秒
}
} catch (Exception e) {
System.out.println("Producer Error");
}
}
}
/**
* 消费者
* @author Quan
*
*/
public class Consumer implements Runnable{
private Frame frame; //持有容器对象
private int total;
public Consumer(Frame frame,int i) {
this.frame = frame;
this.total = i;
}
@Override
public void run() {
try {
for(int i = 0; i < total; i++){
Cake cake = new Cake(i);
frame.pop(cake);
Thread.sleep(200); //每吃一个馒头,休眠200毫秒
frame.count();
}
} catch (Exception e) {
System.out.println("Consumer Error");
}
}
}
/**
* 生产者消费者测试主函数
* @author Quan
*
*/
/**
* 生产者消费者测试主函数
* @author Quan
*
*/
public class ProductorConsumer {
public static void main(String[] args) throws Exception {
Frame frame = new Frame();
Consumer consumer = new Consumer(frame,5); //消费6个馒头
Producer producer = new Producer(frame,6); //生产5个馒头
ExecutorService exes = Executors.newCachedThreadPool();
exes.execute(producer);
exes.execute(consumer);
TimeUnit.SECONDS.sleep(5);
exes.shutdownNow();
}
}
运行程序结果:
修改生产消费馒头的数量:
/**
* 生产者消费者测试主函数
* @author Quan
*
*/
public class ProductorConsumer {
public static void main(String[] args) throws Exception {
Frame frame = new Frame();
Consumer consumer = new Consumer(frame,6); //消费6个馒头
Producer producer = new Producer(frame,5); //生产5个馒头
ExecutorService exes = Executors.newCachedThreadPool();
exes.execute(producer);
exes.execute(consumer);
TimeUnit.SECONDS.sleep(5);
exes.shutdownNow();
}
}
程序运行结果:
这里的pop error原因是:在主线程休眠5秒钟后,产生中断信号,消费者在线程在调用pop去取馒头的等待中接到中断信号,退出等待,抛出java.lang.InterruptedException异常,程序退出pop方法,回到消费者的Thread.sleep(200); //每吃一个馒头,休眠200毫秒 位置,依次执,程序正常退出。