zoukankan      html  css  js  c++  java
  • 生产者消费者模式(吃包子样例)

    生产者-消费者问题是一个经典的进程同步问 题,该问题最早由Dijkstra提出。用以演示他提出的信号量机制。在同一个进程地址空间内运行的两个线程生产者线程生产物品,然后将物品放置在一个空 缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,假设没有空缓冲区可用。那么生产者线程必须等待消费 者线程释放出一个空缓冲区。当消费者线程消费物品时。假设没有满的缓冲区,那么消费者线程将被堵塞。直到新的物品被生产出来。

     

    生产者消费者模式是并发、多线程编程中经典的设计模式, 生产者和消费者通过分离的运行工作解耦。简化了开发模式。生产者和消费者能够以不同的速度生产和消费数据。这篇文章我们来看看什么是生产者消费者模式,这 个问题也是多线程面试题中常常被提及的,使用生产者消费者模式的优点。

    真实世界中的生产者消费者模式

    生产者和消费者模式在生活其中随处可见,它描写叙述的是协调与协作的关系。比方一个人正在准备食物(生产者),而还有一个人正在吃(消费者),他们使用一个共用 的桌子用于放置盘子和取走盘子,生产者准备食物。假设桌子上已经满了就等待。消费者(那个吃的)等待假设桌子空了的话。这里桌子就是一个共享的对象。在 Java Executor框架自身实现了生产者消费者模式它们分别负责加入和运行任务。

     

    它的确是一种有用的设计模式,经常使用于编写多线程或并发代码。

    以下是它的一些长处:

    1它简化的开发,你能够独立地或并发的编写消费者和生产者。它只只需知道共享对象是谁

    2生产者不须要知道谁是消费者或者有多少消费者。对消费者来说也是一样

    3生产者和消费者能够以不同的速度运行

    4分离的消费者和生产者在功能上能写出更简洁、可读、易维护的代码  


    生产者消费者问题是一个流行的面试题,面试官会要求你实现生产者消费者设计模式,以至于能让生产者应等待假设队列或篮子满了的话。消费者等待假设队列或者 篮子是空的。这个问题能够用不同的方式来现实,经典的方法是使用wait和notify方法在生产者和消费者线程中合作,在队列满了或者队列是空的条件下 堵塞,Java5的堵塞队列(BlockingQueue)数据结构更简单,由于它隐含的提供了这些控制,尽管如今你不须要使用wait和nofity在生产 者和消费者之间通信了,堵塞队列的put()方法将堵塞假设队列满了。队列take()方法将堵塞假设队列是空的。

    在下部分我们看看jdk5之前怎么用java实现生产者和消费者模式。 

    以下我就用吃包子者样例


    生产者:包子生产者(多个)。一次生产一个包子,生产的时间是随机的

    缓存区:装包子的篮子(一个),样例里我限定篮子最多能装5个。篮子里面最上面的包子会被先吃掉。所以这用到了数据结构里面的栈,先进后出

    消费者:吃包子的消费者(多个),一次仅仅能吃个包子,吃的时间也是随机的


    篮子满了生产者就不能够往篮子里放包子,必须得等到篮子不是满的

    篮子空了消费者不能够继续吃包子,得等到篮子有包子才干拿包子吃


    代码例如以下

    package com.eyugame.test;
    
    import java.util.Arrays;
    import java.util.Random;
    
    /**
     * 生产者消费者模式 样例:生产包子者(生产者),吃包子者(消费者),放包子的篮子(栈结构,先进后出。由于篮子里面上面的包子会被先吃掉)
     * 
     * @author JYC506
     * 
     */
    /* 放包子的篮子 */
    public class StackPack {
    	/* 篮子的大小 */
    	private int maxSize;
    	/* 用来存放包子的数组 */
    	private Object[] data;
    	/* 最上面包子的位置 */
    	private int top;
    
    	/* 构造方法 */
    	public StackPack(int maxSize) {
    		this.maxSize = maxSize;
    		this.data = new Object[maxSize];
    		this.top = -1;
    	}
    
    	/**
    	 * 从篮子拿出一个包子
    	 * @param eaterName 包子消费者的名字
    	 * @return
    	 */
    	public synchronized Object eat(String eaterName) {
    		/* 假设篮子为空就等到篮子有包子为止 */
    		while (this.isEmpty()) {
    			System.out.println("篮子空了++++++++++消费者"+eaterName+"得等一下再吃了");
    			try {
    				this.wait();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		this.notify();
    		Object object = data[top];
    		data[top]=null;
    		System.out.println(eaterName+"吃了"+object);
    		top--;
    		return object;
    	}
    
        /**
         * 加入包子
         * @param object 包子
         * @param name 生产者的名称
         * @return
         */
    	public synchronized boolean add(Object object,String name) {
    		/* 假设篮子满了就等到篮子能够放包子为止 */
    		while (this.isFull()) {
    			System.out.println("篮子满了-----------生产者"+name+"要等一下再生产");
    			try {
    				this.wait();
    			} catch (InterruptedException e) {
    				e.printStackTrace();
    			}
    		}
    		this.notify();
    		if (object != null) {
    			this.top++;
    			data[top] = object;
    			this.show();
    			return true;
    		}
    		return false;
    	}
    
    	/* 推断篮子是否为空 */
    	private boolean isEmpty() {
    		return this.top == -1;
    	}
    
    	/* 推断篮子是否满了 */
    	private boolean isFull() {
    		return this.top == maxSize - 1;
    	}
    	
    	private void show(){
    		System.out.println("篮子里面的包子:"+Arrays.toString(data));
    	}
    
    	public static void main(String[] args) {
    		/* 创建装包子的篮子 */
    		StackPack stackPack = new StackPack(5);
    		/* 创建两个生产者,生产的包子放stackPack这个篮子。满了就不能再生产得等 */
    		BunHandler bunProducer1 = new BunProducer(stackPack,"A");
    		BunHandler bunProducer2 = new BunProducer(stackPack,"B");
    		/* 创建3个消费者,吃stackPack篮子里面的包子,篮子假设没有包子得等 */
    		BunHandler bunCustomer1 = new BunCustomer(stackPack,"a");
    		BunHandler bunCustomer2 = new BunCustomer(stackPack,"b");
    		BunHandler bunCustomer3 = new BunCustomer(stackPack,"c");
    		/* 生产者開始生产包子 */
    		bunProducer1.start();
    		bunProducer2.start();
    		/* 消费者開始吃包子 */
    		bunCustomer1.start();
    		bunCustomer2.start();
    		bunCustomer3.start();
    	}
    }
    
    /* 生产者:生产包子的生产者 */
    class BunProducer extends BunHandler {
    
    	/* 构造方法 */
    	public BunProducer(StackPack stackPack, String name) {
    		super(stackPack, name);
    	}
    
    	/**
    	 * 随机时间生产包子
    	 */
    	@Override
    	void toDo() {
    		try {
    			while (true) {
    				this.stackPack.add("包子" + name,name);
    				Thread.sleep(this.random.nextInt(2000) + 1000);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    
    /* 消费者:吃包子的消费者 */
    class BunCustomer extends BunHandler {
    	/*构造方法*/
    	public BunCustomer(StackPack stackPack, String name) {
    		super(stackPack, name);
    	}
    	/**
    	 * 假设篮子没空的话1到3秒随机时间吃一个
    	 */
    	@Override
    	void toDo() {
    		try {
    			while (true) {
    				this.stackPack.eat(this.name);
    				Thread.sleep(this.random.nextInt(4000) + 2000);
    			}
    		} catch (Exception e) {
    			e.printStackTrace();
    		}
    	}
    }
    
    /*跟包子有关的抽象对象*/
    abstract class BunHandler extends Thread {
    	/* 用来产生随机时间 */
    	Random random = new Random();
    	/* 从指定篮子拿包子 */
    	StackPack stackPack;
    	/* 名称 */
    	String name;
    	/**
    	 * 
    	 * @param stackPack 篮子
    	 * @param name  有关对象的名称
    	 */
    	public BunHandler(StackPack stackPack, String name) {
    		this.stackPack = stackPack;
    		this.name=name;
    	}
    
    	@Override
    	public void run() {
    		this.toDo();
    	}
    
    	abstract void toDo();
    }
    測试结果



  • 相关阅读:
    MySQL体系结构
    Java线程池ThreadPoolExecuter:execute()原理
    Java Thread 如何处理未捕获的异常?
    SSL/TSL握手过程详解
    LockSupport HotSpot里park/unpark的实现
    JAVA 对象内存结构
    JAVA 线程状态转换
    Spring源码解析(四)Bean的实例化和依赖注入
    Spring源码解析(五)循环依赖问题
    Spring源码解析(三)BeanDefinition的载入、解析和注册
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5183194.html
Copyright © 2011-2022 走看看