wait与notifyAll实现简单的生产者消费者模式

前面转载了一篇用BlockingQueue实现生产者消费者模式的文章。文中提到了另外一种实现方式,利用对象的wait以及notifyAll方法。

先贴上代码:

package com.demo.test;

import java.util.ArrayList;
import java.util.List;

public class ProducerConsumer {
	public static void main(String[] args) {
		// 建立仓库
		MyStack stack = new MyStack();
		// 生产者
		Producer producer = new Producer(stack);
		// 消费者
		Consumer consumer = new Consumer(stack);

		// 开始生产
		new Thread(producer).start();
		// 开始消费
		new Thread(consumer).start();
	}

	/**
	 * 产品类
	 * 
	 * @author kk
	 * 
	 */
	private static class Product {
		private int id;

		public Product(int productId) {
			this.id = productId;
		}

		@Override
		public String toString() {
			return "product" + id;
		}
	}

	/**
	 * 生产者, 负责生产产品
	 * 
	 * @author kk
	 * 
	 */
	private static class Producer implements Runnable {
		private String name = "生产者";
		private MyStack myStack;

		public Producer(MyStack stack) {
			this.myStack = stack;
		}

		@Override
		public void run() {
			for (int i = 0; i < 10; i++) {
				// System.out.println("生产" + i);
				// 生产产品
				Product product = new Product(i);
				// 入库
				myStack.push(product);
				// 休息下
				try {
					Thread.sleep(200);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}
	}

	/**
	 * 消费者,消费产品
	 * 
	 * @author kk
	 * 
	 */
	private static class Consumer implements Runnable {
		private String name = "消费者";
		private MyStack myStack;

		public Consumer(MyStack stack) {
			this.myStack = stack;
		}

		@Override
		public void run() {
			for (int i = 0; i < 10; i++) {
				// System.out.println("消费" + i);
				// 产品出库
				Product product = myStack.pop();
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}

		}
	}

	/**
	 * 实现自己的仓库,用来存放产品
	 * 
	 * @author kk
	 * 
	 */
	private static class MyStack {
		private List<Product> products = new ArrayList<Product>();// 存放产品

		/**
		 * 从仓库中获取产品来消费
		 * 
		 * @return
		 */
		public synchronized Product pop() {
			// 如果仓库已经消费空了,那你就等着新品上市吧
			if (products.size() == 0) {
				System.out.println("仓库已经空了,等待生产...");
				try {
					this.wait();
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			this.notifyAll();// 通知生产
			// 仓库没空,从仓库中拿出一个产品
			Product product = products.get(0);
			products.remove(product);
			System.out.println("产品出库:" + product);
			return product;
		}

		/**
		 * 将生产者生产的产品入库
		 * 
		 * @param producedProduct
		 */
		public synchronized void push(Product producedProduct) {
			// 如果当前仓库已经满了
			if (products.size() >= 5) {
				System.out.println("仓库已经满啦,没地方放了,快停止生产吧,通知消费者来消费");
				try {
					this.wait();// 停止生产
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			this.notifyAll();// 通知消费
			// 仓库未满,既然生产了就入库吧
			products.add(producedProduct);
			System.out.println("\t产品入库:" + producedProduct);
		}

	}
}


运行结果:

仓库已经空了,等待生产...
	产品入库:product0
产品出库:product0
	产品入库:product1
	产品入库:product2
产品出库:product1
	产品入库:product3
	产品入库:product4
	产品入库:product5
产品出库:product2
	产品入库:product6
	产品入库:product7
产品出库:product3
	产品入库:product8
仓库已经满啦,没地方放了,快停止生产吧,通知消费者来消费
产品出库:product4
	产品入库:product9
产品出库:product5
产品出库:product6
产品出库:product7
产品出库:product8
产品出库:product9


Notes:

1,wait()必须在synchronized 函数或者代码块里面,wait会让synchronized函数或者代码块所在线程暂时的停止运行,释放锁,丧失控制权,该线程进入等待,

让其它的线程有机会获得控制权,在条件满足的情况下调用notifyAll()来唤醒正在wait的线程,等待获取cpu时间,获取到后,继续往下执行;

2,生产者Producer和消费者Consumer要共用仓库MyStack;

3,notifyAll()方法是唤醒其他正在等待的线程,并不让出自己的cpu时间,还是会继续运行;

4,仓库空了,消费者wait,通知生产者赶紧生产notifyAll。仓库满了,生产者wait,通知消费者赶紧消费notifyAll;




你可能感兴趣的:(thread,编程,并发,线程,concurrency)