生产者消费者模式并不是GOF提出的23种设计模式之一,23种设计模式都是建立在面向对象的基础之上的,但其实面向过程的编程中也有很多高效的编程模式,生产者消费者模式便是其中之一,它是我们编程过程中最常用的一种设计模式。
生产者消费者模式是为了解决哪一类问题而产生的呢?在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。单单抽象出生产者和消费者,还够不上是生产者/消费者模式。该模式还需要有一个缓冲区处于生产者和消费者之间,作为一个中介。生产者把数据放入缓冲区,而消费者从缓冲区取出数据。
生产者消费者的关系如下图所示:

生产者消费者模式的原理描述:
(1)生产者仅仅在仓储未满时候生产,仓满则停止生产。
(2)消费者仅仅在仓储有产品时候才能消费,仓空则等待。
(3)当消费者发现仓储没产品可消费时候会通知生产者生产。
(4)生产者在生产出可消费产品时候,应该通知等待的消费者去消费。
下面通过一个例子描述下生产者消费者模式的使用。
1、第一个文件ProductStorage.java
2、第二个文件Producter.java
3、第三个文件Consumer.java
4、第四个文件TestMain.java
5、生产者消费者模式的优点:
(1)将生产模块和消费模块分隔开,从而降低了程序的耦合,便于程序的扩展和维护。
(2)将生产模块和消费模块的分隔,可使生产模块的运行不再依赖消费模块的执行,由同步改为异步执行并且都可支持并发,从而大大提高了程序的效率。
(3)生成者生产的数据存放在缓冲区中,消费者可以按照自己的逻辑来取出数据处理,从而可以有效避免消费模块任务执行负载不均的问题。
生产者消费者模式是为了解决哪一类问题而产生的呢?在实际的软件开发过程中,经常会碰到如下场景:某个模块负责产生数据,这些数据由另一个模块来负责处理(此处的模块是广义的,可以是类、函数、线程、进程等)。产生数据的模块,就形象地称为生产者;而处理数据的模块,就称为消费者。单单抽象出生产者和消费者,还够不上是生产者/消费者模式。该模式还需要有一个缓冲区处于生产者和消费者之间,作为一个中介。生产者把数据放入缓冲区,而消费者从缓冲区取出数据。
生产者消费者的关系如下图所示:

生产者消费者模式的原理描述:
(1)生产者仅仅在仓储未满时候生产,仓满则停止生产。
(2)消费者仅仅在仓储有产品时候才能消费,仓空则等待。
(3)当消费者发现仓储没产品可消费时候会通知生产者生产。
(4)生产者在生产出可消费产品时候,应该通知等待的消费者去消费。
下面通过一个例子描述下生产者消费者模式的使用。
1、第一个文件ProductStorage.java
点击(此处)折叠或打开
-
/**
-
* 库存商品管理类
-
*/
-
public class ProductStorage {
-
-
/**
-
* 最大库存量
-
*/
-
public static final int Maximum = 100;
-
-
/**
-
* 当前库存量
-
*/
-
public static int Currentimum = 50;
-
-
/**
-
* 库存管理实例
-
*/
-
private static ProductStorage instance;
-
-
private ProductStorage(){}
-
-
/**
-
* 获取单例
-
* @return
-
*/
-
public static ProductStorage getInstance(){
-
if(instance == null){
-
instance = new ProductStorage();
-
}
-
return instance;
-
}
-
-
/**
-
* 生产产品
-
*/
-
public synchronized void product(){
-
while(Currentimum >= Maximum/2){
-
try {
-
wait();
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
}
-
Currentimum++;
-
System.out.println("当前线程:"+Thread.currentThread().getName() + "--生产者生产了一个商品,当前库存量:"+ Currentimum);
-
notifyAll();
-
}
-
-
/**
-
* 消费产品
-
*/
-
public synchronized void consume(){
-
while(Currentimum <= 0){
-
try {
-
wait();
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
}
-
Currentimum--;
-
System.out.println("当前线程:"+Thread.currentThread().getName() + "--消费者消费了一个商品,当前库存量:"+ Currentimum);
-
notifyAll();
-
}
- }
2、第二个文件Producter.java
点击(此处)折叠或打开
-
/**
-
* 商品生产者模型
-
*/
-
public class Producter implements Runnable {
-
-
@Override
-
public void run(){
-
while(true){
-
try {
-
Thread.sleep(500);
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
ProductStorage.getInstance().product();
-
}
-
}
- }
点击(此处)折叠或打开
-
/**
-
* 商品消费者模型
-
*/
-
public class Consumer implements Runnable{
-
-
@Override
-
public void run() {
-
while(true){
-
try {
-
Thread.sleep(1000);
-
} catch (InterruptedException e) {
-
e.printStackTrace();
-
}
-
ProductStorage.getInstance().consume();
-
}
-
-
}
- }
点击(此处)折叠或打开
-
import java.util.concurrent.ExecutorService;
-
import java.util.concurrent.Executors;
-
-
public class TestMain {
-
-
public static void main(String [] args){
-
startProductThread();
-
startConsumThread();
-
}
-
-
/**
-
* 开启生产者线程
-
*/
-
public static void startProductThread(){
-
System.out.println("--生产者线程执行开始--");
-
int pThreadSize = 10;
-
ExecutorService pool = Executors.newFixedThreadPool(pThreadSize);
-
for(int i=0;i<pThreadSize;i++){
-
Producter productThread = new Producter();
-
Thread thread = new Thread(productThread);
-
pool.execute(thread);
-
}
-
System.out.println("--生产者线程执行结束--");
-
}
-
-
/**
-
* 开启消费者线程
-
*/
-
public static void startConsumThread(){
-
System.out.println("--消费者线程执行开始--");
-
int pThreadSize = 10;
-
ExecutorService pool = Executors.newFixedThreadPool(pThreadSize);
-
for(int i=0;i<pThreadSize;i++){
-
Consumer consumeThread = new Consumer();
-
Thread thread = new Thread(consumeThread);
-
pool.execute(thread);
-
}
-
System.out.println("--消费者线程执行结束--");
-
}
- }
5、生产者消费者模式的优点:
(1)将生产模块和消费模块分隔开,从而降低了程序的耦合,便于程序的扩展和维护。
(2)将生产模块和消费模块的分隔,可使生产模块的运行不再依赖消费模块的执行,由同步改为异步执行并且都可支持并发,从而大大提高了程序的效率。
(3)生成者生产的数据存放在缓冲区中,消费者可以按照自己的逻辑来取出数据处理,从而可以有效避免消费模块任务执行负载不均的问题。