JAVA生产者消费者模式的实现

春节回了趟老家,又体验了一次流水席,由于桌席多,导致上菜慢,于是在等待间,总结了一下出菜流程的几个特点:

1.有多个灶台,多个灶台都在同时做菜出来。

2.做出来的菜,会有专人用一个托盘端出来,每次端出来的菜(是同一个菜品)的数量不等。

3.由于端出来的菜可能不能满足所有的桌数,所以,端菜人可能会随机选择几桌(一般是就近原则,或者是主桌先端过去)上菜,其余的桌数继续等待后面的端菜人出来。

以上3个条件,完全就是一个生产者消费者模式的场景,于是,把生产者消费者模式先来实现一下,然后再分析如何才能更快的上菜 :)

首先,我们把托盘给虚拟成一个资源池,表示这个托盘里是放菜的,当托盘里的菜大于1时,即有菜品被生产出来,端菜人就要端出去,当托盘里没有菜时,外面所有的桌席都要等待:

(需要特别注意的是,这个资源池只能有一个实例化对象,就像托盘的数量是固定的一样。)

public class ResourcePool {

	private int number = 0;

	public synchronized void producer(){
		try {
			while(number==3){
				this.wait();
			}
			number++;
			System.out.println("producer: "+number);
			this.notifyAll();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public synchronized void consumer(){
		try {
			while(number==0){
				this.wait();
			}
			number--;
			System.out.println("consumer: "+number);
			this.notifyAll();
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

}

其实,我们要有灶台,这个灶台是专门做菜的,做出来的菜,当然是全部放在了资源池(即托盘中),灶台是会有多个的,所以要继承thread类:

public class ResourceProduce extends Thread{

	private ResourcePool rp;

	public ResourceProduce(ResourcePool rp) {
		this.rp = rp;
	}

	public void run() {
		rp.producer();
	}

}

托盘中有了菜,就得端出去了,给送到外面的桌席上去,由于桌席是多桌,所以,也要继承thread类:

public class ResourceConsumer extends Thread{

	private ResourcePool rp;

	public ResourceConsumer(ResourcePool rp) {
		this.rp = rp;
	}

	public void run() {
		rp.consumer();
	}

}

这些基础的设施都准备好后,我们的端菜人就出来了:

public class ResourceUtil {

	public void resource(){
		ResourcePool rp = new ResourcePool();
		for (int i = 0; i < 3; i++) {
			new ResourceProduce(rp).start();
		}
		for (int i = 0; i < 5; i++) {
			new ResourceConsumer(rp).start();
		}
	}

	public static void main(String[] args) {
		ResourceUtil ru = new ResourceUtil();
		ru.resource();
	}

}

我们来看一下最后的输出结果:

当只有三个灶台,而桌席有5桌时,程序就等待下去了,于是,当我们把灶台数改成5后,运行结果:

producer: 1
producer: 2
producer: 3
consumer: 2
producer: 3
consumer: 2
producer: 3
consumer: 2
consumer: 1
consumer: 0

通过上面的程序运行,如果想上菜速度快,还是得加灶台,多加厨师,当然,这只是就这个场景简单的分析了一下,可能还会有更复杂的因素没考虑到,举这个例子的主要意思,是想让多多的理解一下生产者消费者模式,该模式我们平常可能用原生的比较少,但其实使用的场景一直都在用,比如线程池,连接池,等等。所以,知其然也知其所以然也很有必要,我们接着就代码来说明一下这个实现代码中的重点:

1.资源池有且只有一个。

2.synchronized,是锁对象,简单说一下:一个对象有且只有一把锁,当有多个synchronized方法或代码块都向该对象申请锁时,在同一时间,只会有一个线程得到该锁并运行,其它的就被阻塞了。

3.wait,是指该线程等待,wait有一个很重要的点,就是释放锁,上面也说了synchronized在同一时间只会有一个线程得到该锁并运行,所以,一旦wait后,就会释放锁,但当前线程等待下去,其它的线程再竞争这把锁。

4.notifyAll是指唤醒当前对象的所有等待的线程。

5.所有唤醒的线程会同时去竞争这把锁,但是JVM会随机选择一个线程并分配这把锁给该线程。

6.上面的synchronized wait notifyAll都是对一个对象进行操作,但这三个都是用在了资源池的类里面,所以,这也是资源池有且只能有一个的原因。

后绪:至于生产者消费者模式能给我们测试带来什么样的帮助,我暂时还没想到,但了解一下,出去面试时,有很大的可能性会被问到,有兴趣的,就当作一种知识储备吧。

时间: 2024-10-26 03:20:34

JAVA生产者消费者模式的实现的相关文章

基于Java 生产者消费者模式(详细分析)

本文目录:1.等待.唤醒机制的原理2.Lock和Condition3.单生产者单消费者模式4.使用Lock和Condition实现单生产单消费模式5.多生产多消费模式(单面包)6.多生产多消费模式 生产者消费者模式是多线程中最为常见的模式:生产者线程(一个或多个)生成面包放进篮子里(集合或数组),同时,消费者线程(一个或多个)从篮子里(集合或数组)取出面包消耗.虽然它们任务不同,但处理的资源是相同的,这体现的是一种线程间通信方式. 本文将先说明单生产者单消费者的情况,之后再说明多生产者多消费者模

java生产者/消费者模式实现——一生产者一消费者(操作值)

胶多不粘话多不甜,直接上代码: 生产者类: /** * Created by 51304 on 2016/2/28. */ public class P { private String lock; public P(String lock){ this.lock = lock; } public void setValue(){ try{ synchronized (this.lock){ if(!ValueObject.value.equals("")){ lock.wait();

Java 并发编程(四)阻塞队列和生产者-消费者模式

阻塞队列 阻塞队列提供了可阻塞的 put 和 take 方法,以及支持定时的 offer 和 poll 方法.如果队列已经满了,那么put方法将阻塞直到有空间可以用:如果队列为空,那么take方法将一直阻塞直到有元素可用.队列可以使有界的,也可以是无界的,无界队列永远都不会充满,因此无界队列上的put方法永远不会阻塞.一种常见的阻塞生产者-消费者模式就是线程池与工作队列的组合,在 Executor 任务执行框架中就体现了这种模式. 意义:该模式能简化开发过程,因为他消除了生产者和消费者类之间的代

java设计模式之生产者/消费者模式

什么是生产者/消费者模式? 某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类.函数.线程.进程等).产生数据的模块,就形象地称为生产者:而处理数据的模块,就称为消费者.在生产者与消费者之间在加个缓冲区,我们形象的称之为仓库,生产者负责往仓库了进商品,而消费者负责从仓库里拿商品,这就构成了生产者消费者模式.结构图如下: 生产者消费者模式有如下几个优点: 1.解耦   由于有缓冲区的存在,生产者和消费者之间不直接依赖,耦合度降低. 2.支持并发   由于生产者与消费

Java线程同步与死锁、生产者消费者模式以及任务调度等

一.Thread类基本信息方法 package Threadinfo; public class MyThread implements Runnable{ private boolean flag = true; private int num = 0; @Override public void run() { while(flag) { System.out.println(Thread.currentThread().getName()+"-->"+num++); } }

java 多线程并发系列之 生产者消费者模式的两种实现

在并发编程中使用生产者和消费者模式能够解决绝大多数并发问题.该模式通过平衡生产线程和消费线程的工作能力来提高程序的整体处理数据的速度. 为什么要使用生产者和消费者模式 在线程世界里,生产者就是生产数据的线程,消费者就是消费数据的线程.在多线程开发当中,如果生产者处理速度很快,而消费者处理速度很慢,那么生产者就必须等待消费者处理完,才能继续生产数据.同样的道理,如果消费者的处理能力大于生产者,那么消费者就必须等待生产者.为了解决这种生产消费能力不均衡的问题,所以便有了生产者和消费者模式. 什么是生

生产者消费者模式的java实现(实现三)

Exchanger是java.util.concurrent类库下的一个并发工具.下面是java api文档里对Exchanger的描述. A synchronization point at which threads can pair and swap elements within pairs. Each thread presents some object on entry to the exchange method, matches with a partner thread, a

java 多线程 22 :生产者/消费者模式 进阶 利用await()/signal()实现

java多线程15 :wait()和notify() 的生产者/消费者模式 在这一章已经实现了  wait/notify 生产消费模型 利用await()/signal()实现生产者和消费者模型 一样,先定义一个缓冲区: public class ValueObject { public static String value = ""; } 换种写法,生产和消费方法放在一个类里面: public class ThreadDomain41 extends ReentrantLock {

生产者消费者模式的java实现(实现二)

这次采用ReentrantLock 实现生产者消费者模式,先说下ReentrantLock,通常叫做重入锁,所谓重入就是一个线程可以再次进入已经持有锁的代码块,在内部会对重入的次数进行计数,当计数为0,则释放锁.其实synchronized关键字所代表的内置锁,也是可以重入的.但是又有几点不同: 1.ReentrantLock将加锁与解锁进行分离,可以提供更细粒度的加解锁操作,内置锁基本都是全局锁(类,对象,代码块) 2.ReentrantLock提供了定时的加锁操作,这是内置锁无法做到的. 3