生产者和消费者在同一时间段内共用同一段存储空间,生产者向空间里生产数据,而消费者取走数据。
工厂里面汽车的零件生产与汽车组装是同时进行的,其中我们定义以下规则
汽车组装必须有足够的零件支持零件生产与汽车组装(有足够的零件)互不影响为避免浪费,零件的储存上限为5(我们抽象为1个零件可以生产一辆汽车)下面我们使用wait() / notify()方法与await() / signal()方法对我们的场景进行模拟
在这里我们对wait() / notify()进行一个简单的介绍
wait():当缓冲区已满/空时,生产者/消费者线程停止自己的执行,放弃锁,使自己处于等待状态,让其他线程执行。notify()方法:当生产者/消费者向缓冲区放入/取出一个产品时,向其他等待的线程发出可执行的通知,同时放弃锁,使自己处于等待状态 //缓冲区 class Storage{ //存储零件 private LinkedList<Object> list = new LinkedList<Object>(); //最大存储数量 private int MAX_NUMBER = 5; //生产零件计数器 private int produceCount = 0; //组装零件计数器 private int consumeCount = 0; //生产零件 public void produce() { synchronized (list) { //零件太多,停止生产 while(list.size() >= MAX_NUMBER) { try { list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //恢复生产 Object object = new Object(); list.add(object); System.out.println("生产第" + (++produceCount) + "个零件,仓库还有" + list.size() + "个零件"); list.notify(); } } //组装零件 public void consume() { synchronized (list) { //零件太少,无法组装 while(list.size() <= 0) { try { list.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //恢复组装 list.removeFirst(); System.out.println("组装第" + (++consumeCount) + "个零件,仓库还有" + list.size() + "个零件"); list.notify(); } } } //生产者,即生产零件的工作小组 class Producer implements Runnable{ private Storage storage; public Producer(Storage storage) { this.storage = storage; } @Override public void run() { //生产50个零件 for(int i=0;i<50;i++) { storage.produce(); } } } //消费者,即组装零件的工作小组 class Consumer implements Runnable{ private Storage storage; public Consumer(Storage storage) { this.storage = storage; } @Override public void run() { //组装50个零件 for(int i=0;i<50;i++) { storage.consume(); } } } public class Demo{ public static void main(String[] args) { Storage storage = new Storage(); new Thread(new Consumer(storage)).start(); new Thread(new Producer(storage)).start(); } }部分运行结果,读者可以自行运行上面那段代码,在自己电脑查看完整结果
生产第1个零件,仓库还有1个零件 组装第1个零件,仓库还有0个零件 生产第2个零件,仓库还有1个零件 生产第3个零件,仓库还有2个零件 组装第2个零件,仓库还有1个零件 组装第3个零件,仓库还有0个零件 生产第4个零件,仓库还有1个零件 组装第4个零件,仓库还有0个零件 生产第5个零件,仓库还有1个零件 生产第6个零件,仓库还有2个零件 生产第7个零件,仓库还有3个零件 生产第8个零件,仓库还有4个零件 生产第9个零件,仓库还有5个零件 组装第5个零件,仓库还有4个零件 组装第6个零件,仓库还有3个零件 组装第7个零件,仓库还有2个零件 组装第8个零件,仓库还有1个零件 组装第9个零件,仓库还有0个零件 生产第10个零件,仓库还有1个零件 生产第11个零件,仓库还有2个零件 生产第12个零件,仓库还有3个零件 生产第13个零件,仓库还有4个零件 生产第14个零件,仓库还有5个零件 组装第10个零件,仓库还有4个零件 组装第11个零件,仓库还有3个零件 (略)
await()和signal()的功能基本上和wait() / nofity()相同,完全可以取代它们,但是它们和Lock直接挂钩,具有更大的灵活性。通过在Lock对象上调用newCondition()方法,将条件变量和一个锁对象进行绑定,进而控制并发程序访问竞争资源的安全。
下面我们进行代码模拟
//缓冲区 class Storage{ //锁 private final Lock lock = new ReentrantLock(); //仓库满的条件变量 private final Condition full = lock.newCondition(); //仓库空的条件变量 private final Condition empty = lock.newCondition(); //存储零件 private LinkedList<Object> list = new LinkedList<Object>(); //最大存储数量 private int MAX_NUMBER = 5; //生产零件计数器 private int produceCount = 0; //组装零件计数器 private int consumeCount = 0; //生产零件 public void produce() { lock.lock(); //零件太多,停止生产 while(list.size() >= MAX_NUMBER) { try { full.await(); } catch (InterruptedException e) { e.printStackTrace(); } } //恢复生产 Object object = new Object(); list.add(object); System.out.println("生产第" + (++produceCount) + "个零件,仓库还有" + list.size() + "个零件"); empty.signal(); lock.unlock(); } //组装零件 public void consume() { lock.lock(); //零件太少,无法组装 while(list.size() <= 0) { try { empty.await(); } catch (InterruptedException e) { e.printStackTrace(); } } //恢复组装 list.removeFirst(); System.out.println("组装第" + (++consumeCount) + "个零件,仓库还有" + list.size() + "个零件"); full.signal(); lock.unlock(); } } //生产者,即生产零件的工作小组 class Producer implements Runnable{ private Storage storage; public Producer(Storage storage) { this.storage = storage; } @Override public void run() { //生产50个零件 for(int i=0;i<50;i++) { storage.produce(); } } } //消费者,即组装零件的工作小组 class Consumer implements Runnable{ private Storage storage; public Consumer(Storage storage) { this.storage = storage; } @Override public void run() { //组装50个零件 for(int i=0;i<50;i++) { storage.consume(); } } } public class Demo{ public static void main(String[] args) { Storage storage = new Storage(); new Thread(new Consumer(storage)).start(); new Thread(new Producer(storage)).start(); } }结果一切正常,证明代码无误
参考:生产者/消费者问题的多种Java实现方式
