JAVA 多线程经典案例-生产者消费者模型【使用wait/notify实现】

生产者消费者模型实现细节

生产者生产产品到公共仓库,消费者消费公共仓库中产品。

情况一:当公共仓库产品达到仓库容量上限,生产者停止生产;

情况二:当公共仓库没有产品,或达到设置的仓库容量下限,消费者停止消费;

情况三:当公共仓库产品达到容量上限时,消费者消费一次,就可以让生产者继续生产;

情况四:当公共仓库没有产品时,生产者生产一次,就可以让消费者继续消费;

功能实现说明

公共仓库 ,包含“仓库容量上限”、“仓库容量下限”、“当前容量”基础属性,及“入库”、“出库”基础方法;

生产者 ,包含“所属仓库”、“每次生产数量”基础属性,及“生产存入仓库”基础方法;

消费者 ,包含“所属仓库”、“每次消费数量”基础属性,及“仓库取出消费”基础方法;

代码实现

公共仓库 ,抽取“入库”、“出库”基础方法作为接口,后续可通过实现该接口,重写方法来实现;

(1)公共仓库接口

/** *@date2018年12月11日 *@methodputIn(int num) //往仓库中存入指定数量的产品 *@methodoutOf(int num) //从仓库中取出制定数量的产品 */interfaceAbstractStorage{voidputIn(intnum);voidoutOf(intnum);}

(2)仓库实现类

仓库类只需判断库存量是否达到存入/取出阈值,从而限制生产者/消费者的存入/取出,不需要使用循环来判断;

/** *@date2018年12月11日 *@paramMAX_PRODUCT //仓库容量上限 *@paramMIN_PRODUCT //仓库容量下限 *@paramstock //仓库当前容量,属于共享资源 *@methodputIn(int) //当(库存+即将存入)大于容量上限,停止存入 *@methodoutOf(int) //当(库存-即将取出)小于容量上限,停止取出 */classStorageimplementsAbstractStorage{publicfinalintMAX_PRODUCT =10;publicfinalintMIN_PRODUCT =0;privateintstock;@OverridepublicsynchronizedvoidputIn(intnum){if((stock + num) >= MAX_PRODUCT) {System.out.println("库存已满!");try{wait();}catch(InterruptedException e) {e.printStackTrace();}}else{stock += num;System.out.println(Thread.currentThread().getName() +"存入,库存:"+ stock);notifyAll();}}@OverridepublicsynchronizedvoidoutOf(intnum){if((stock - num) <= MIN_PRODUCT) {System.out.println("库存已空!");try{wait();}catch(InterruptedException e) {e.printStackTrace();}}else{stock -= num;System.out.println(Thread.currentThread().getName() +"取出,库存:"+ stock);notifyAll();}}publicintgetStock(){returnstock;}publicvoidsetStock(intstock){this.stock = stock;}}

生产者

使用实现Runnable接口方式创建生产者线程,将生产者生产操作放到重写的run()方法中,实现生产者线程生产;

/** *@Data2018年12月11日 *@paramstorage //公共仓库 *@paramnum //生产数量 *@constructorProduce(AbstractStorage) //构造器 *@methodprod(int) //生产者生产方法 *@methodrun() //生产者线程执行方法 *@methodsetNum(int) //设置生产者每次生产数量 */classProducerimplementsRunnable{privateAbstractStorage storage;privateintnum;publicProducer(AbstractStorage storage){this.storage = storage;}@Overridepublicvoidrun(){prod(num);}privatevoidprod(intnum){while(true) {try{Thread.sleep(100);//需要添加延时,不然生产者线程获得执行权时,一瞬间即可生产到仓库上限值}catch(InterruptedException e) {e.printStackTrace();}storage.putIn(num);}}publicvoidsetNum(intnum){this.num = num;}}

消费者

使用实现Runnable接口方式创建消费者线程,将消费者消费操作放到重写的run()方法中,实现消费者线程消费;

/** *@Data2018年12月11日 *@paramstorage //公共仓库 *@paramnum //生产数量 *@constructorConsume(AbstractStorage) //构造器 *@methodcons(int) //消费者生产方法 *@methodrun() //消费者线程执行方法 *@methodsetNum(int) //设置消费者每次生产数量 */classConsumerimplementsRunnable{privateAbstractStorage storage;privateintnum;publicConsumer(AbstractStorage storage){this.storage = storage;}@Overridepublicvoidrun(){cons(num);}privatevoidcons(intnum){while(true) {try{Thread.sleep(100);//需要添加延时,不然消费者线程获得执行权时,一瞬间即可消费到仓库下限值}catch(InterruptedException e) {e.printStackTrace();}storage.outOf(num);}}publicvoidsetNum(intnum){this.num = num;}

测试类

/**

* @Date 2018年12月11日

* @param storage //创建公共仓库

* @param producer //创建生产者线程

* @param consumer //创建消费者线程

*/public class TestA {public static void main(String[] args) {AbstractStorage storage = new Storage();Producer producer = new Producer(storage);Consumer consumer = new Consumer(storage);producer.setNum(2);consumer.setNum(1);Threadt1= new Thread(producer);Threadt2= new Thread(consumer);t1.setName("producer");t2.setName("consumer");t1.start();t2.start();}}

测试输出

写在最后的话

使用wait/notify方法实现,很多时候会出现一些奇怪的问题,例如:

1、两者都持有锁且等待对方释放锁,造成死锁的情况;

2、对未持有锁的对象进行释放锁,导致IllegalMonitorStateException异常;

3、加锁时,双方所加的锁并非同一把锁,导致数据异常;

关于生产者/消费者模型,现在更多是使用阻塞队列(Queue)的方式来实现,后续会接着去学习那一块知识。

【注】以上为本人通过网上视频教程以及实例代码整理所得,如果出错以及更好的提议,欢迎留言指正,一起学习。

---------------------

每天都在分享文章,也每天都有人想要我出来给大家分享下怎么去学习Java。大家都知道,我们是学Java全栈的,大家就肯定以为我有全套的Java系统教程。没错,我是有Java全套系统教程,进扣裙【47】974【9726】所示,进群的时候记得表明自己想要学习什么,不要用小号,这样小编才好给你们发定向资源,今天小编就免费送!~

后记:对于大部分转行的人来说,找机会把自己的基础知识补齐,边工作边补基础知识,真心很重要。“我们相信人人都可以成为一个程序员,现在开始,找个师兄,带你入门,学习的路上不再迷茫。这里是ja+va修真院,初学者转行到互联网行业的聚集地。"

你可能感兴趣的:(JAVA 多线程经典案例-生产者消费者模型【使用wait/notify实现】)