恭喜辛勤的鱼摊主今日生意火热,瞬间就售空掉捕捞到的鱼。
这里我们把卖鱼当作产出方,顾客当作消费方,其实就是个生产与消费的例子。而生产与消费无处不在,工厂生产玩偶,消费者购买玩偶;餐厅里厨师炒菜,食客吃菜;市场买菜的阿姨卖菜,妈妈们去买菜等等。
假若生产的商品放置于仓库(鱼摊主捕鱼将鱼放置于鱼篓),那么仓库(鱼篓)肯定有个上限,而当仓库无商品(鱼篓无鱼)时候,消费者也无处消费。
我们又如何确保,仓库(鱼篓)满的时候生产者(鱼摊主)停止生产(捕鱼)直到仓库(鱼篓)可以继续存放商品(鱼),仓库(鱼篓)空的时候消费者停止消费直到仓库(鱼篓)有库存(有鱼)?
生产者和消费者是两个独立的并发事件,生产者(鱼摊主他老婆也去捕鱼啦!)生产商品的同时消费者也可能在消费商品。
生产与消费是多线程的经典例子之一,主要涉及到
1.线程等待唤醒
2.同步锁机制
那么我们来看看代码是如何现实的?(注释的地方请注意下)
public class ProducerAndConsumer { public static void main(String[] args){ List<Object> goods = new ArrayList<>(); Thread p1=new Thread(new Producer(goods,"Producer1")); p1.start(); Thread c1 = new Thread(new Consumer(goods,"Consumer1")); c1.start(); Thread c2 = new Thread(new Consumer(goods,"Consumer2")); c2.start(); Thread c3 = new Thread(new Consumer(goods,"Consumer3")); c3.start(); Thread p2 = new Thread(new Producer(goods,"Producer2")); p2.start(); } public static class Producer implements Runnable{ private List<Object> goods; private String name; public Producer(List<Object> goods,String name){ this.name = name; this.goods = goods; } public void product() throws InterruptedException { synchronized (goods){//synchronized同步锁goods while(goods.size()==10){ System.out.println(Thread.currentThread().getName()+" "+name+" "+" goods is full"); goods.wait();//线程进入等待状态,并且释放锁goods } //商品没有满或者处于等待状态的某生产线程唤醒后,执行以下代码 goods.add(new Object()); System.out.println(Thread.currentThread().getName()+" "+name+" product,now goods'count is "+goods.size()); goods.notifyAll();//唤醒在等待的线程 } } @Override public void run() { try { product(); } catch (InterruptedException e) { e.printStackTrace(); } } } public static class Consumer implements Runnable{ private List<Object> goods; private String name; public Consumer(List<Object> goods,String name){ this.name = name; this.goods = goods; } public void consume() throws InterruptedException { synchronized (goods){//synchronized同步锁goods while(goods.size()==0){ System.out.println(Thread.currentThread().getName()+" "+name+" "+" goods is empty"); goods.wait();//线程进入等待状态,释放锁goods; } //商品没有空或者处于等待状态的某消费线程唤醒后,执行以下代码 goods.remove(0); System.out.println(Thread.currentThread().getName()+" "+name+" consume,now goods'count is "+goods.size()); goods.notifyAll();//唤醒在等待的线程 } } @Override public void run() { try { consume(); } catch (InterruptedException e) { e.printStackTrace(); } } } }
输出结果(结果顺序不一定相同)
Thread-0 Producer1 product,now goods'count is 1 Thread-1 Consumer1 consume,now goods'count is 0 Thread-2 Consumer2 goods is empty Thread-3 Consumer3 goods is empty Thread-4 Producer2 product,now goods'count is 1 Thread-3 Consumer3 consume,now goods'count is 0 Thread-2 Consumer2 goods is empty
本文就只用这个wait/notifyAll来实现生产与消费,但其实还有很多种实现方式,大家可以自己思考下。
从这个多线程经典例子中可以学习到很多有趣的或者你忽略的点。
谢谢大家观阅!
本人公众号程序员七猫,不定期更新!
请多多关注和支持!
(第一时间发布在微信公众号上,所以若是喜欢的朋友可以关注哦)