场景描述:
一个仓库,生产者在工厂里生产了产品后,将产品存放到仓库里,仓库存放数量有限,当满仓后,停 止生产,直到有消费着将产品消费后才继续生产;消费者从仓库里提取产品,当仓库空仓时,停止消费产 品,直到仓库中有产品时,才继续消费产品。
代码的实现(调整线程sleep时间可以实现生产速度与消费速度的不同):
TestProduceAndConsumer.java
package com.nantian;import java.util.Random;public class TestProduceAndConsumer { public static void main(String[] args) { // 创建一个工厂对象 ProductFacTory pf = new ProductFacTory(); // 创建一个生产者和一个消费者,传递工厂的引用,保证两者操作的是同一个工厂 Producer p = new Producer(pf); Consumer c = new Consumer(pf); // 启动两个线程 p.start(); c.start(); }}// 产品工厂class ProductFacTory { // product表示仓库 private char[] product = { ' ', ' ', ' ', ' ', ' '}; // flag标记产品数量 private int flag = 0; // 生产产品 public synchronized void produceProduct(char p) throws InterruptedException { // 判断产品是否满仓,以便决定是否继续生产 if (flag == product.length) { this.wait(); } // 当代码执行到这里,一定不是满仓状态 product[flag++] = p; // 查看此时仓库状态(这里不属于业务逻辑部分) System.out.print(p + "被生产,当前仓库状态:"); for (char tmp : product) { System.out.print(tmp); } System.out.println(); // 生产方法完成,如果存在等待队列中的线程,应该唤醒 this.notifyAll(); } // 消费产品 public synchronized char consumeProduct() throws InterruptedException { // 判断仓库是否空仓,以便决定是否消费产品 if(flag == 0) { this.wait(); } // 当代码执行到这里,一定不是空仓状态 char p = product[--flag]; product[flag]=' '; // 查看此时仓库状态(这里不属于业务逻辑部分) System.out.print(p + "被消费,当前仓库状态:"); for(char tmp : product) { System.out.print(tmp); } System.out.println(); // 消费方法完成,如果存在等待队列中的线程,应该唤醒 this.notifyAll(); return p; }}// 生产者class Producer extends Thread { private ProductFacTory pf = null; public Producer(ProductFacTory pf) { this.pf = pf; } public void run() { // 一共生产20个产品 for(int i=0; i<20; i++) { // 随机产生一个大写字母作为产品 Random r = new Random(); char p = (char)(r.nextInt(26) + 'A'); try { // 产品入库 pf.produceProduct(p); // 故意sleep,以便消费线程有机会获得CPU时间片,方便演示 Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } } }}// 消费者class Consumer extends Thread { private ProductFacTory pf = null; public Consumer(ProductFacTory pf) { this.pf = pf; } public void run() { // 一共消费20个产品 for(int i=0; i<20; i++) { try { // 产品出库 pf.consumeProduct(); // 故意sleep,以便生产线程有机会获得CPU时间片,方便演示 // sleep时间稍微错开,阻止同时竞争CPU时间片 Thread.sleep(300); } catch (InterruptedException e) { e.printStackTrace(); } } }}
获得幸福的二法门是珍惜你所拥有的、遗忘你所没有的