前言:程序开发中,可能会碰到这种情景,就是一边生产,一边消耗;一方面不能无限制的生产,会导致溢出,也不能无限制的消耗;就比如飞机大战游戏,敌机(生产者)不可能一瞬间出现很多,需要控制其数量,结合我们消灭敌机的速度(消费者),还有植物大战僵尸游戏也是这个原理
1.基本概念
生产者—消费者模型用于协调生产数据和使用数据的线程:
- 生产者:向仓库中添加数据。
- 消费者:从仓库中取出数据。
- 共享仓库:存放数据,生产者和消费者操作的是同一个仓库。
仓库满时,生产者等待;仓库空时,消费者等待。当仓库状态发生变化,就通知等待的线程继续尝试工作。
本文使用 List 模拟仓库,最大容量为 20。
privatefinalList<Integer>list;privatestaticfinalintMax=20;2. 实现步骤
1.先创建这样一个仓库
privatefinalList<Integer>list;2.将仓库对象传给生产者和消费者
3.用对象锁保护仓库(由于数据共享,必然存在线程安全问题,要用对象锁)
synchronized(list){if(list.size()<=Max){list.add(1);list.notify();}4.如果碰到仓库满了,此时生产者线程就陷入等待,直到下次被唤醒,继续生产;消费者是如果仓库为空,就停止消费,进入等待,直到被唤醒。
if(list.size()<=Max){list.add(1);list.notify();}else{try{list.wait();}catch(InterruptedExceptione){Thread.currentThread().interrupt();return;}System.out.println("仓库已经,生产者进入等待状态...");if(!list.isEmpty()){list.remove(0);System.out.println("消费一个,仓库数量:"+list.size());}else{try{list.wait();}catch(InterruptedExceptione){Thread.currentThread().interrupt();return;3.关键代码说明
1.对象锁锁定的是共享的那个库,也就是list
synchronized(list)所有线程都使用同一个 list 作为锁。同一时刻,只有一个线程能够进入这些同步代码块。
判断条件和实际操作必须放在一起保护。例如,判断仓库未满之后,不能让另一个线程插进来把仓库填满,再继续添加数据。
- wait():等待并释放锁
list.wait();当前线程进入等待,同时释放 list 的锁,让其他线程有机会操作仓库。
线程被唤醒后,需要重新获得这把锁,才能从 wait() 后面继续执行。
3. notifyAll():通知等待的线程
list.notify();它会唤醒在 list 上等待的所有线程。这些线程随后竞争锁,拿到锁后才能继续执行。
调用 notifyAll() 的线程不会立即释放锁,要等它退出同步代码块。
4.以下为完整代码
publicclassProducerimplementsRunnable{privatefinalList<Integer>list;privatestaticfinalintMax=20;publicProducer(List<Integer>list){this.list=list;}publicvoidrun(){while(true){synchronized(list){if(list.size()<=Max){list.add(1);list.notify();}else{try{list.wait();}catch(InterruptedExceptione){Thread.currentThread().interrupt();return;}System.out.println("仓库已经,生产者进入等待状态...");}}}}}publicclassConsumerimplementsRunnable{privatefinalList<Integer>list;publicConsumer(List<Integer>list){this.list=list;}publicvoidrun(){while(true){synchronized(list){if(!list.isEmpty()){list.remove(0);System.out.println("消费一个,仓库数量:"+list.size());}else{try{list.wait();}catch(InterruptedExceptione){Thread.currentThread().interrupt();return;}}}}}}publicclassManage{publicstaticvoidmain(String[]args){List<Integer>list=newArrayList<>();Producerproducer=newProducer(list);Consumerconsumer=newConsumer(list);newThread(producer,"生产者1").start();newThread(producer,"生产者2").start();newThread(consumer,"消费者1").start();newThread(consumer,"消费者2").start();}}