[置顶] java多线程同步:生产者与消费者问题

生产者与消费者问题问题是线程同步里边一个很经典的问题。

用通俗的语言来描述:一群生产者不断的生产产品,并将产品放到一个容器里边;同时一群消费者不断从容器里边消费产品。

容器的容量是有限的。如果容器满了,生产者不能再往容器放产品,必须进入等待状态。等待产品被消费者拿走了,再往容器放产品。

同样,如果容器空了,消费者也必须进入等待状态。等待生产者往里边放产品,再将消费者唤醒。

下边我们来看看如何用java代码来实现

我们假设生产者是一群厨师,产品是面包,容器是一个篮子,消费者是一群消费者。

用面向对象的思维来考虑,我们要至少要定义4个类

先定义好面包类

/*
 *面包类,用于存放厨师生产的面包
 */
public class Bread {
	private String producer;

	public Bread(String producer) {
		super();
		this.producer = producer;
	}

	@Override
	public String toString() {
		return producer;
	}
}

再定义一个篮子类

/*
 * 篮子类,用于存放面包
 * 篮子假定最多放10个面包
 */
public class Basket {
	private int index = 0;
	private Bread[] arrayBread = new Bread[10];

	/*
	 * 此方法用于往篮子里扔面包 每当厨师生成好一个面包就往篮子里边扔 由于当某一个厨师在往篮子扔面包的过程(还没扔完,但是面包已经在篮子里),
	 * 又有一个厨师要往篮子里扔面包。 如果这是篮子里已经有9个面包的话,最后一个厨师就不能在扔了。
	 * 所以需要给这个方法加把锁,等一个厨师扔完后,另外一个厨师才能往篮子里扔。
	 */
	public synchronized void push(int id, Bread bread) {
		System.out.println("生成前篮子里有面包:" + index + " 个");
		// 当厨师发现篮子满了,就在那里不停的等着
		while (index == arrayBread.length) {
			System.out.println("篮子满了,我开始等等。。。。。。");
			try {
				// 厨师(一个生产线程)开始不停等待
				// 他需要等待顾客(一个消费线程)把它叫醒
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		// 唤醒一个正在等待的线程,如果唤醒的线程为生产线程,则又会进入等待状态,
		// 如果为消费线程,则因生产线程生产了面包的缘故,消费线程可以进行消费
		this.notify();
		arrayBread[index] = bread;
		index++;
		System.out.println(bread);

	}

	/*
	 * 此方法用于往篮子里拿面包 加锁原因和上边一样
	 */
	public synchronized Bread pop(int id) {
		System.out.println("消费前篮子里有面包:" + index + " 个");
		while (index == 0) {
			System.out.println("篮子空了,我开始等等。。。。。。");
			try {
				// 顾客(一个消费线程)开始不停等待
				// 他需要等待厨师(一个生产线程)把它叫醒
				this.wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}

		// 唤醒一个正在等待的线程,如果唤醒的线程为消费线程,则又会进入等待状态,
		// 如果为生产线程,则因生产线程消费了面包的缘故,生产线程可以进行生产
		this.notify();
		index--;
		System.out.println("第" + id + "个顾客消费了 -->" + arrayBread[index]);
		return arrayBread[index];
	}
}

再定义一个厨师类

/*
 * 厨师类,用于生产面包
 */
public class Kitchener implements Runnable {
	private Basket basket;
	private int id;

	public Kitchener(int id,Basket basket) {
		super();
		this.id = id;
		this.basket = basket;
	}

	@Override
	public void run() {
		//让厨师生产10个面包
		for (int i = 1; i <= 10; i++) {
			Bread bread = new Bread("第" + id + "个厨师生成的面包");
			basket.push(id,bread);
			
			
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

}

最后定义顾客类

/*
 * 顾客类,用于消费面包
 */
public class Customer implements Runnable {
	private Basket basket;
	private int id;
	public Customer(int id,Basket basket) {
		super();
		this.id = id;
		this.basket = basket;
	}

	@Override
	public void run() {
		// 让顾客消费10个面包
		for (int i = 1; i <= 10; i++) {
			basket.pop(id);
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}

	}

}


好我们就可以来测试一下代码

public class Test {
	public static void main(String[] args) {
		Basket basket = new Basket();
		// 两个厨师两个客户
		Kitchener kitchener1 = new Kitchener(1,basket);
		Kitchener kitchener2 = new Kitchener(2,basket);
		Customer customer1 = new Customer(1,basket);
		Customer customer2 = new Customer(2,basket);
		new Thread(kitchener1).start();
		new Thread(kitchener2).start();
		new Thread(customer1).start();
		new Thread(customer2).start();
	}

}


运行结果

生成前篮子里有面包:0 个
第1个厨师生成的面包
消费前篮子里有面包:1 个
第2个顾客消费了 -->第1个厨师生成的面包
消费前篮子里有面包:0 个
篮子空了,我开始等等。。。。。。
生成前篮子里有面包:0 个
第2个厨师生成的面包
第1个顾客消费了 -->第2个厨师生成的面包
生成前篮子里有面包:0 个
第2个厨师生成的面包
生成前篮子里有面包:1 个
第1个厨师生成的面包
生成前篮子里有面包:2 个
第2个厨师生成的面包
生成前篮子里有面包:3 个
第1个厨师生成的面包
生成前篮子里有面包:4 个
第2个厨师生成的面包
生成前篮子里有面包:5 个
第1个厨师生成的面包
生成前篮子里有面包:6 个
第2个厨师生成的面包
生成前篮子里有面包:7 个
第1个厨师生成的面包
生成前篮子里有面包:8 个
第2个厨师生成的面包
生成前篮子里有面包:9 个
第1个厨师生成的面包
生成前篮子里有面包:10 个
篮子满了,我开始等等。。。。。。
生成前篮子里有面包:10 个
篮子满了,我开始等等。。。。。。
消费前篮子里有面包:10 个
第2个顾客消费了 -->第1个厨师生成的面包
第2个厨师生成的面包
篮子满了,我开始等等。。。。。。
消费前篮子里有面包:10 个
第1个顾客消费了 -->第2个厨师生成的面包
第1个厨师生成的面包
生成前篮子里有面包:10 个
篮子满了,我开始等等。。。。。。
生成前篮子里有面包:10 个
篮子满了,我开始等等。。。。。。
消费前篮子里有面包:10 个
第2个顾客消费了 -->第1个厨师生成的面包
第2个厨师生成的面包
篮子满了,我开始等等。。。。。。
消费前篮子里有面包:10 个
第1个顾客消费了 -->第2个厨师生成的面包
第1个厨师生成的面包
生成前篮子里有面包:10 个
篮子满了,我开始等等。。。。。。
生成前篮子里有面包:10 个
篮子满了,我开始等等。。。。。。
消费前篮子里有面包:10 个
第1个顾客消费了 -->第1个厨师生成的面包
第2个厨师生成的面包
篮子满了,我开始等等。。。。。。
消费前篮子里有面包:10 个
第2个顾客消费了 -->第2个厨师生成的面包
第1个厨师生成的面包
生成前篮子里有面包:10 个
篮子满了,我开始等等。。。。。。
生成前篮子里有面包:10 个
篮子满了,我开始等等。。。。。。
消费前篮子里有面包:10 个
第1个顾客消费了 -->第1个厨师生成的面包
第2个厨师生成的面包
篮子满了,我开始等等。。。。。。
消费前篮子里有面包:10 个
第2个顾客消费了 -->第2个厨师生成的面包
第1个厨师生成的面包
消费前篮子里有面包:10 个
第1个顾客消费了 -->第1个厨师生成的面包
消费前篮子里有面包:9 个
第2个顾客消费了 -->第2个厨师生成的面包
消费前篮子里有面包:8 个
第1个顾客消费了 -->第1个厨师生成的面包
消费前篮子里有面包:7 个
第2个顾客消费了 -->第2个厨师生成的面包
消费前篮子里有面包:6 个
第1个顾客消费了 -->第1个厨师生成的面包
消费前篮子里有面包:5 个
第2个顾客消费了 -->第2个厨师生成的面包
消费前篮子里有面包:4 个
第1个顾客消费了 -->第1个厨师生成的面包
消费前篮子里有面包:3 个
第2个顾客消费了 -->第2个厨师生成的面包
消费前篮子里有面包:2 个
第1个顾客消费了 -->第1个厨师生成的面包
消费前篮子里有面包:1 个
第2个顾客消费了 -->第2个厨师生成的面包



你可能感兴趣的:(多线程,消费者,生产者,同步)