生产者与消费者问题问题是线程同步里边一个很经典的问题。
用通俗的语言来描述:一群生产者不断的生产产品,并将产品放到一个容器里边;同时一群消费者不断从容器里边消费产品。
容器的容量是有限的。如果容器满了,生产者不能再往容器放产品,必须进入等待状态。等待产品被消费者拿走了,再往容器放产品。
同样,如果容器空了,消费者也必须进入等待状态。等待生产者往里边放产品,再将消费者唤醒。
下边我们来看看如何用java代码来实现
我们假设生产者是一群厨师,产品是面包,容器是一个篮子,消费者是一群消费者。
用面向对象的思维来考虑,我们要至少要定义4个类
先定义好面包类
/* *面包类,用于存放厨师生产的面包 */ public class Bread { private String producer; public Bread(String producer) { super(); this.producer = producer; } @Override public String toString() { return producer; } }
/* * 篮子类,用于存放面包 * 篮子假定最多放10个面包 */ public class Basket { private int index = 0; private Bread[] arrayBread = new Bread[10]; /* * 此方法用于往篮子里扔面包 每当厨师生成好一个面包就往篮子里边扔 由于当某一个厨师在往篮子扔面包的过程(还没扔完,但是面包已经在篮子里), * 又有一个厨师要往篮子里扔面包。 如果这是篮子里已经有9个面包的话,最后一个厨师就不能在扔了。 * 所以需要给这个方法加把锁,等一个厨师扔完后,另外一个厨师才能往篮子里扔。 */ public synchronized void push(int id, Bread bread) { System.out.println("生成前篮子里有面包:" + index + " 个"); // 当厨师发现篮子满了,就在那里不停的等着 while (index == arrayBread.length) { System.out.println("篮子满了,我开始等等。。。。。。"); try { // 厨师(一个生产线程)开始不停等待 // 他需要等待顾客(一个消费线程)把它叫醒 this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 唤醒一个正在等待的线程,如果唤醒的线程为生产线程,则又会进入等待状态, // 如果为消费线程,则因生产线程生产了面包的缘故,消费线程可以进行消费 this.notify(); arrayBread[index] = bread; index++; System.out.println(bread); } /* * 此方法用于往篮子里拿面包 加锁原因和上边一样 */ public synchronized Bread pop(int id) { System.out.println("消费前篮子里有面包:" + index + " 个"); while (index == 0) { System.out.println("篮子空了,我开始等等。。。。。。"); try { // 顾客(一个消费线程)开始不停等待 // 他需要等待厨师(一个生产线程)把它叫醒 this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } // 唤醒一个正在等待的线程,如果唤醒的线程为消费线程,则又会进入等待状态, // 如果为生产线程,则因生产线程消费了面包的缘故,生产线程可以进行生产 this.notify(); index--; System.out.println("第" + id + "个顾客消费了 -->" + arrayBread[index]); return arrayBread[index]; } }
/* * 厨师类,用于生产面包 */ public class Kitchener implements Runnable { private Basket basket; private int id; public Kitchener(int id,Basket basket) { super(); this.id = id; this.basket = basket; } @Override public void run() { //让厨师生产10个面包 for (int i = 1; i <= 10; i++) { Bread bread = new Bread("第" + id + "个厨师生成的面包"); basket.push(id,bread); try { Thread.sleep(1); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
/* * 顾客类,用于消费面包 */ public class Customer implements Runnable { private Basket basket; private int id; public Customer(int id,Basket basket) { super(); this.id = id; this.basket = basket; } @Override public void run() { // 让顾客消费10个面包 for (int i = 1; i <= 10; i++) { basket.pop(id); try { Thread.sleep(2000); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } }
public class Test { public static void main(String[] args) { Basket basket = new Basket(); // 两个厨师两个客户 Kitchener kitchener1 = new Kitchener(1,basket); Kitchener kitchener2 = new Kitchener(2,basket); Customer customer1 = new Customer(1,basket); Customer customer2 = new Customer(2,basket); new Thread(kitchener1).start(); new Thread(kitchener2).start(); new Thread(customer1).start(); new Thread(customer2).start(); } }
生成前篮子里有面包:0 个 第1个厨师生成的面包 消费前篮子里有面包:1 个 第2个顾客消费了 -->第1个厨师生成的面包 消费前篮子里有面包:0 个 篮子空了,我开始等等。。。。。。 生成前篮子里有面包:0 个 第2个厨师生成的面包 第1个顾客消费了 -->第2个厨师生成的面包 生成前篮子里有面包:0 个 第2个厨师生成的面包 生成前篮子里有面包:1 个 第1个厨师生成的面包 生成前篮子里有面包:2 个 第2个厨师生成的面包 生成前篮子里有面包:3 个 第1个厨师生成的面包 生成前篮子里有面包:4 个 第2个厨师生成的面包 生成前篮子里有面包:5 个 第1个厨师生成的面包 生成前篮子里有面包:6 个 第2个厨师生成的面包 生成前篮子里有面包:7 个 第1个厨师生成的面包 生成前篮子里有面包:8 个 第2个厨师生成的面包 生成前篮子里有面包:9 个 第1个厨师生成的面包 生成前篮子里有面包:10 个 篮子满了,我开始等等。。。。。。 生成前篮子里有面包:10 个 篮子满了,我开始等等。。。。。。 消费前篮子里有面包:10 个 第2个顾客消费了 -->第1个厨师生成的面包 第2个厨师生成的面包 篮子满了,我开始等等。。。。。。 消费前篮子里有面包:10 个 第1个顾客消费了 -->第2个厨师生成的面包 第1个厨师生成的面包 生成前篮子里有面包:10 个 篮子满了,我开始等等。。。。。。 生成前篮子里有面包:10 个 篮子满了,我开始等等。。。。。。 消费前篮子里有面包:10 个 第2个顾客消费了 -->第1个厨师生成的面包 第2个厨师生成的面包 篮子满了,我开始等等。。。。。。 消费前篮子里有面包:10 个 第1个顾客消费了 -->第2个厨师生成的面包 第1个厨师生成的面包 生成前篮子里有面包:10 个 篮子满了,我开始等等。。。。。。 生成前篮子里有面包:10 个 篮子满了,我开始等等。。。。。。 消费前篮子里有面包:10 个 第1个顾客消费了 -->第1个厨师生成的面包 第2个厨师生成的面包 篮子满了,我开始等等。。。。。。 消费前篮子里有面包:10 个 第2个顾客消费了 -->第2个厨师生成的面包 第1个厨师生成的面包 生成前篮子里有面包:10 个 篮子满了,我开始等等。。。。。。 生成前篮子里有面包:10 个 篮子满了,我开始等等。。。。。。 消费前篮子里有面包:10 个 第1个顾客消费了 -->第1个厨师生成的面包 第2个厨师生成的面包 篮子满了,我开始等等。。。。。。 消费前篮子里有面包:10 个 第2个顾客消费了 -->第2个厨师生成的面包 第1个厨师生成的面包 消费前篮子里有面包:10 个 第1个顾客消费了 -->第1个厨师生成的面包 消费前篮子里有面包:9 个 第2个顾客消费了 -->第2个厨师生成的面包 消费前篮子里有面包:8 个 第1个顾客消费了 -->第1个厨师生成的面包 消费前篮子里有面包:7 个 第2个顾客消费了 -->第2个厨师生成的面包 消费前篮子里有面包:6 个 第1个顾客消费了 -->第1个厨师生成的面包 消费前篮子里有面包:5 个 第2个顾客消费了 -->第2个厨师生成的面包 消费前篮子里有面包:4 个 第1个顾客消费了 -->第1个厨师生成的面包 消费前篮子里有面包:3 个 第2个顾客消费了 -->第2个厨师生成的面包 消费前篮子里有面包:2 个 第1个顾客消费了 -->第1个厨师生成的面包 消费前篮子里有面包:1 个 第2个顾客消费了 -->第2个厨师生成的面包