生产者和消费者问题
一、维基百科
生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多进程同步问题的经典案例。该问题描述了共享固定大小缓冲区的两个进程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。
要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据。同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者。通常采用进程间通信的方法解决该问题,常用的方法有**信号灯法**[1]等。如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形
二、实战问题
采用Java 多线程技术,设计实现一个符合生产者和消费者问题的程序。对一个对象(枪膛)进行操作,其最大容量是12颗子弹。生产者线程是一个压入线程, 它不断向枪膛中压入子弹;消费者线程是一个射出线程,它不断从枪膛中射出子弹。
wait()和notify()方法实现
1、枪的实体类
public class Gun {
//临界资源
protected final List<Bullet> bullets = new ArrayList<Bullet>();
public int size() {
return bullets.size();
}
public void pushBullet() {
bullets.add(new Bullet());
}
public void pullBullet() {
bullets.remove(0);
}
protected int count;
public Gun() {
int count = 0;
}
//子弹
class Bullet{
}
}
2、射出子弹的线程
public class PullBullet implements Runnable {
private Gun gun;
public PullBullet(Gun gun) {
super();
this.gun = gun;
}
public void run() {
try {
while(true){
synchronized (gun.bullets) {
Thread.currentThread().sleep(500);
while(gun.size() == 0) {
//弹夹(缓冲区)为空时,该线程等待,进入休眠状态
gun.bullets.wait();
}
//射出子弹就会唤醒线程
gun.bullets.notifyAll();
gun.pullBullet();
System.out.println("Pull Bullet ..."+gun.size());
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
3、压入子弹线程
public class PushBullet implements Runnable {
private Gun gun;
public PushBullet(Gun gun) {
super();
this.gun = gun;
}
public void run() {
try {
while(true){
synchronized (gun.bullets) {
Thread.currentThread().sleep(500);
while(gun.size() == 12) {
gun.bullets.wait();
}
gun.bullets.notifyAll();
gun.pushBullet();
System.out.println("Push Bullet ..."+gun.size());
}
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
4、启动类
public static void main(String[]args) {
Gun gun = new Gun();
Thread push = new Thread(new PushBullet(gun));
push.setName("push");
push.start();
Thread pull = new Thread(new PullBullet(gun));
pull.setName("pull");
pull.start();
}
5、输出