生产者和消费者问题

一、维基百科

  生产者消费者问题(英语: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、输出