生产者/消费者模式是面向过程的一种高效设计模式。
生产者/消费者模式定义:
生产者消费者模式是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。
这个阻塞队列就是用来给生产者和消费者解耦的。纵观大多数设计模式,都会找一个第三者出来进行解耦,如工厂模式的第三者是工厂类,模板模式的第三者是模板类。在学习一些设计模式的过程中,如果先找到这个模式的第三者,能帮助我们快速熟悉一个设计模式。
生产者/消费者模式原理:
1、生产者仅仅在仓库未满时进行成产,满仓则停止生产。
2、消费者仅仅在仓库有存量时才进行消费,否则停止消费。
3、生产者生产出产品后将通知消费者进行消费。
4、消费者停止消费时将通知生产者开始生产。
下面用代码来解释一下生产者/消费者模式
1、定义一个仓库,也就是产品管理类
/**
* 管理类
* @author Administrator
*
*/
public class ProductManager {
//缓存最大数量
private static final int MAX = 100;
//当前数量
private static int current = 60;
//构造方法
private ProductManager(){};
//获取单例
public static ProductManager getInstance(){
return ProductSingleton.productManager;
}
//静态内部类
private static class ProductSingleton{
static ProductManager productManager = new ProductManager();
}
//创建商品
public synchronized void setProduct(){
while (current > MAX/2){
//停止生产
try {
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
current++;
System.out.println("++++当前线程:"+Thread.currentThread().getName() +
"--生产了一个产品,当前库存还有:"+ current + "个");
//通知消费者线程
notifyAll();
}
//消费商品
public synchronized void getProduct(){
while(current < 1){
try {
// 停止消费
wait();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
current--;
System.out.println("----当前线程:"+Thread.currentThread().getName() +
"--消费了一个产品,当前库存还有:"+ current + "个");
//通知生产者线程
notifyAll();
}
}
仓库只有有个,所以采用的单例模式创建仓库实例。仓库中定义了容量以及当前存量,以及生产的方法和消费的方法,用于生产者和消费者调用。
2、定义生产者线程。
/**
* 生产者线程
* @author Administrator
*
*/
public class Producer implements Runnable{
@Override
public void run() {
while(true){
//获取单例,生产产品
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ProductManager.getInstance().setProduct();
}
}
}
3、定义消费者线程
/**
* 消费者线程
* @author Administrator
*
*/
public class Consumer implements Runnable{
@Override
public void run() {
while(true){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ProductManager.getInstance().getProduct();
}
}
}
4、测试
/**
* 测试
* @author Administrator
*
*/
public class Test {
public static void main(String[] args) {
startProducer();
startConsumer();
}
private static void startConsumer() {
System.out.println("消费者线程执行开始");
int iThreadSize = 10;
Executor pool = Executors.newFixedThreadPool(iThreadSize);
for(int i = 0 ; i < iThreadSize ; i++){
pool.execute(new Thread(new Consumer()));
}
System.out.println("消费者线程执行结束");
}
private static void startProducer() {
System.out.println("生产者线程执行开始");
int iThreadSize = 10;
Executor pool = Executors.newFixedThreadPool(iThreadSize);
for(int i = 0 ; i < iThreadSize ; i++){
pool.execute(new Thread(new Producer()));
}
System.out.println("生产者线程执行结束");
}
}
测试中,我开启了10个生产者,10个消费者,当然,实际当中也有差距。接下来就让我们的整个系统跑起来看看。
生产者线程执行开始
生产者线程执行结束
消费者线程执行开始
消费者线程执行结束
----当前线程:pool-2-thread-9--消费了一个产品,当前库存还有:59个
----当前线程:pool-2-thread-10--消费了一个产品,当前库存还有:58个
----当前线程:pool-2-thread-6--消费了一个产品,当前库存还有:57个
----当前线程:pool-2-thread-1--消费了一个产品,当前库存还有:56个
----当前线程:pool-2-thread-4--消费了一个产品,当前库存还有:55个
----当前线程:pool-2-thread-5--消费了一个产品,当前库存还有:54个
----当前线程:pool-2-thread-8--消费了一个产品,当前库存还有:53个
----当前线程:pool-2-thread-2--消费了一个产品,当前库存还有:52个
----当前线程:pool-2-thread-3--消费了一个产品,当前库存还有:51个
----当前线程:pool-2-thread-7--消费了一个产品,当前库存还有:50个
++++当前线程:pool-1-thread-8--生产了一个产品,当前库存还有:51个
----当前线程:pool-2-thread-10--消费了一个产品,当前库存还有:50个
++++当前线程:pool-1-thread-9--生产了一个产品,当前库存还有:51个
----当前线程:pool-2-thread-9--消费了一个产品,当前库存还有:50个
++++当前线程:pool-1-thread-5--生产了一个产品,当前库存还有:51个
----当前线程:pool-2-thread-1--消费了一个产品,当前库存还有:50个
++++当前线程:pool-1-thread-10--生产了一个产品,当前库存还有:51个
----当前线程:pool-2-thread-4--消费了一个产品,当前库存还有:50个
----当前线程:pool-2-thread-3--消费了一个产品,当前库存还有:49个
...
因为是在循环当中个,所以这整个程序会一直跑下去,看输出结果,有条不紊,各司己职。
以上就是生产和消费者的介绍、原理和使用。