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

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

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

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

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

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

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

功能实现说明

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

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

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

代码实现

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

(1)公共仓库接口

 
/** * @date 2018年12月11日 * @method putIn(int num) //往仓库中存入指定数量的产品 * @method outOf(int num) //从仓库中取出制定数量的产品 */ interface AbstractStorage { void putIn(int num); void outOf(int num); } 

(2)仓库实现类

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

 
/** * @date 2018年12月11日 * @param MAX_PRODUCT //仓库容量上限 * @param MIN_PRODUCT //仓库容量下限 * @param stock //仓库当前容量,属于共享资源 * @method putIn(int) //当(库存+即将存入)大于容量上限,停止存入 * @method outOf(int) //当(库存-即将取出)小于容量上限,停止取出 */ class Storage implements AbstractStorage { public final int MAX_PRODUCT = 10; public final int MIN_PRODUCT = 0; private int stock; @Override public synchronized void putIn(int num) { 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(); } } @Override public synchronized void outOf(int num) { 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(); } } public int getStock() { return stock; } public void setStock(int stock) { this.stock = stock; } } 

生产者

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

 
/** * @Data 2018年12月11日 * @param storage //公共仓库 * @param num //生产数量 * @constructor Produce(AbstractStorage) //构造器 * @method prod(int) //生产者生产方法 * @method run() //生产者线程执行方法 * @method setNum(int) //设置生产者每次生产数量 */ class Producer implements Runnable { private AbstractStorage storage; private int num; public Producer(AbstractStorage storage) { this.storage = storage; } @Override public void run() { prod(num); } private void prod(int num) { while (true) { try { Thread.sleep(100); //需要添加延时,不然生产者线程获得执行权时,一瞬间即可生产到仓库上限值 } catch (InterruptedException e) { e.printStackTrace(); } storage.putIn(num); } } public void setNum(int num) { this.num = num; } } 

消费者

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

 
/** * @Data 2018年12月11日 * @param storage //公共仓库 * @param num //生产数量 * @constructor Consume(AbstractStorage) //构造器 * @method cons(int) //消费者生产方法 * @method run() //消费者线程执行方法 * @method setNum(int) //设置消费者每次生产数量 */ class Consumer implements Runnable { private AbstractStorage storage; private int num; public Consumer(AbstractStorage storage) { this.storage = storage; } @Override public void run() { cons(num); } private void cons(int num) { while (true) { try { Thread.sleep(100); //需要添加延时,不然消费者线程获得执行权时,一瞬间即可消费到仓库下限值 } catch (InterruptedException e) { e.printStackTrace(); } storage.outOf(num); } } public void setNum(int num) { 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); Thread t1 = new Thread(producer); Thread t2 = 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修真院,初学者转行到互联网行业的聚集地。"

猜你喜欢

转载自blog.csdn.net/qq_41552245/article/details/86146695