写在前面的话,学习编程已经有一段时间了。一直感觉没有系统的概念,仔细想一想应该是自己没有总结归纳。很多时候自己当一个知识接收者,这样对于知识的掌握和理解都不够深刻。正如某人云,当一个知识的输出者才能让自己水平提升。所以以后的日子里我会把自己学习的经历分享出来,希望大神可以多多指教。
鉴于本人水平有限,对于知识的见解可能有片面的地方,仅以此做参考,同时有失偏颇的地方希望在评论中指出。
对于此模型,应该明确一下几点:
1、生产者仅仅在仓储未满时候生产,仓满则停止生产。
2、消费者仅仅在仓储有产品时候才能消费,仓空则等待。
3、当消费者发现仓储没产品可消费时候会通知生产者生产。
4、生产者在生产出可消费产品时候,应该通知等待的消费者去消费。
此模型将要结合java.lang.Object的wait与notify、notifyAll方法来实现以上的需求。这是非常重要的。
在很多编程过程中,是通过现实世界的抽象过来的,这种消费者和生产者模式我们可以抽象为蓄水池的模式;我们可以假设一个蓄水池,这个蓄水池有很多注水口和出水口,当然内部也有很多管道来控制水的流入流出。然后我们就可以把水的注入当成是生产者,水的流入当成是消费者,水池当成是仓库。当遇到高并发的时候如何保证不会出现水的溢出和不可能存在的超量流出(当没有水了还要要求水流出)。
wait()/ nofity()方法是基类Object的两个方法,也就意味着所有Java类都会拥有这两个方法,这样,我们就可以为任何对象实现同步机制。
wait()方法:当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等等状态,让其他线程执行。
notify()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态。
下面我们来看看一个简单的代码,这个代码只是实现了上面说道1,2,4.点。权当是简化版的Demo;
import com.sun.javafx.geom.AreaOp; import java.util.ArrayList; import java.util.List; import java.util.Objects; /**生产和消费模型 * Created by dd on 2017/11/11. */ public class Text_CAP { public static class Factor{ //用于设定最大的数据和装载产品的List private final int MAX_SIZE = 100; private List list=new ArrayList(); //生产方法 public void produce(int mun){ synchronized (list){ System.out.println("当前的库存为"+list.size()); while (list.size()+mun>MAX_SIZE){ System.out.println("生产的数量"+mun+"大于最大可生产数"); try { list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i <mun ; i++) { list.add(new Object()); } list.notifyAll(); System.out.println("生产了"+mun+" 生产后的库存为"+list.size()); } } public void consume(int mun){ synchronized (list){ System.out.println("当前的库存为"+list.size()); while (list.size()<mun){ System.out.println("消费的数量 "+mun+" 大于现有的数量 "+list.size()); try { list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } for (int i = 0; i <mun ; i++) { list.remove(i); } System.out.println("消费了"+mun+" 消费后的库存为"+list.size()); list.notifyAll(); } } public void setList(List list){ this.list=list; } public List getList(){ return list; } public int getMAX_SIZE(){ return this.MAX_SIZE; } } /** * 生产者,作为线程调用生产方法 */ public static class Producer extends Thread{ private Factor factor; private int mun; public Producer (Factor factor){ this.factor=factor; } //调用生产方法 private void produce(int mun){ factor.produce(mun); } //执行调用的方法 这里的run 为什么不直接设置参数呢? // 如果直接设置参数那么Producer内部的num就没有存在的意义了,相当于直接两个嵌套的函数 public void run(){ produce(mun); } public Factor getFactor() { return factor; } public int getMun() { return mun; } public void setFactor(Factor factor) { this.factor = factor; } public void setMun(int mun) { this.mun = mun; } } /** * 消费者,作为线程调用消费方法 */ public static class Consumer extends Thread{ private int mun; private Factor factor; public Consumer(Factor factor){ this.factor=factor; } private void consume(int mun){ factor.consume(mun); } public void run(){ consume(mun); } public Factor getFactor() { return factor; } public int getMun() { return mun; } public void setFactor(Factor factor) { this.factor = factor; } public void setMun(int mun) { this.mun = mun; } } /** * 主函数 * @param arg */ public static void main(String arg[]){ //实例化工厂 Factor factor=new Factor(); //实例化几个消费者 Consumer consumerA = new Consumer(factor); Consumer consumerB = new Consumer(factor); Consumer consumerC = new Consumer(factor); Consumer consumerD = new Consumer(factor); //实例化几个生产者 Producer producerA = new Producer(factor); Producer producerB = new Producer(factor); Producer producerC = new Producer(factor); Producer producerD = new Producer(factor); //设置生产数量,做生产准备 producerA.produce(20); producerB.produce(50); //设置消费数量,做消费准备 consumerA.consume(10); consumerB.consume(20); //执行生产和消费 producerA.start(); producerB.start(); consumerA.start(); consumerB.start(); } }