生产者与消费者问题是Java多线程中一道非常经典的问题,问题如下:
生产者与消费者问题也称缓存问题,生产者与消费者即Java 中的线程,生产者与消费者问题即生产者生产一定数量的线程放入缓存区中,供消费者消费者消费,在消费和生产的过程中,如果生产者生产的产品超过了缓存区的上限则停止生产,等待消费者消费,如果缓存区的产品被消费完,消费者则停止消费,等待生产者生产
首先,我们来看题目,从题目中我们一个可以抽取出几个实体类呢?答案是4个 Consumer(消费者),Producer(生产者),Product(产品),WareHouse(缓冲区,也叫仓库),于是项目结构如下,main 为测试类
产品类
package ProducersAndConsumers; //产品 public class Product { //产品需要一个id 来表明产品的唯一性 private Integer productId; //id直接由构造方法传入 public Product(Integer productId) { this.productId = productId; } public Integer getProductId() { return productId; } @Override public String toString() { return "Product{" + "productId=" + productId + '}'; } }
仓库
package ProducersAndConsumers; import java.util.LinkedList; //仓库类 public class WareHouse { //仓库容量,我们设置为10个 private final int max = 10; //仓库基础的数量 private final int base = 0; //我们设置一个集合来存放生产的产品,由于我们需要一个可以弹出最后一个产品的方法,所以我们在这里使用LinkedList private LinkedList<Product> products = new LinkedList<>(); //生产方法 public synchronized void push(Product product) { //判断是否有空间存放产品 while(max==products.size()){ try{ System.out.println("仓库已满,消费者快来消费"+Thread.currentThread().getName()+"停止生产"); //仓库满后停止当前线程 this.wait(); }catch (Exception ex){ ex.printStackTrace(); } } //生产商品 products.addLast(product); System.out.println(Thread.currentThread().getName()+"生产了一个产品:"+product.getProductId()+"号"); try{ //等待1秒,方面我们观察 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } notifyAll(); } //消费方法 public synchronized void pop() { //判断是否有产品 while (products.size()==base){ try{ System.out.println("仓库空了,生产者快点生产"+Thread.currentThread().getName()+"停止消费"); //仓库空后停止当前线程 this.wait(); } catch (InterruptedException e) { e.printStackTrace(); } } //消费商品 System.out.println(Thread.currentThread().getName()+"消费了一个产品:"+products.getLast().getProductId()+"号"); products.removeLast(); try{ //等待1秒,方面我们观察 Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } notifyAll(); } }
生产者
package ProducersAndConsumers; //生产者 public class Producer implements Runnable { //生产产品的id private int count = 0; //仓库 private WareHouse wareHouse; //生产者和消费者都是用同一个仓库,所以我们只要声明一个仓库,在由构造方法传入即可 public Producer(WareHouse wareHouse) { this.wareHouse = wareHouse; } //生产方法 @Override public void run() { while (true){ Product product = new Product(count); wareHouse.push(product); // 产品id不可重复,所以我们使用自增策略 count++; } } }
消费者
package ProducersAndConsumers; public class Consumer implements Runnable{ //仓库 private WareHouse wareHouse; //生产者和消费者都是用同一个仓库,所以我们只要声明一个仓库,在由构造方法传入即可 public Consumer(WareHouse wareHouse) { this.wareHouse = wareHouse; } //消费方法 @Override public void run() { while (true){ wareHouse.pop(); } } }
最后测试类
package ProducersAndConsumers; //测试类 public class Main { public static void main(String[] args) { WareHouse wareHouse = new WareHouse(); Producer producer = new Producer(wareHouse); Consumer consumer = new Consumer(wareHouse); Thread producerT = new Thread(producer,"生产者"); Thread consumerT = new Thread(consumer,"消费者"); producerT.start(); consumerT.start(); } }