Java-生产者消费者问题

本文详细介绍了生产者消费者问题的经典实现方案,通过多线程模拟生产者与消费者的行为,使用同步机制确保线程间的正确协作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

生产者消费者问题:
生产者消费者问题是一个经典的多线程协作问题。生产者负责生产产品,并将产品存放到仓库;消费者从仓库中获取产品并消费。当仓库满时,生产者必须停止生产,直到仓库有位置存放产品;当仓库为空时,消费者必须停止消费,直到仓库中有产品。

关键技术分析:
—用线程模拟生产者,在run()方法中不断的往仓库 中存放产品。
—用线程模拟消费者,在run()方法中不断的往仓库中获取产品。
—仓库类保存产品,当产品数量为0时,调用wait()方法,使得当前消费者进入线程等待状态,当有新产品调入时,调用notify方法,唤醒等待的消费者线程。当仓库满时,调用wait()方法,使得当前生产者线程进入等待状态,当有消费者获取产品时,调用notify()方法,唤醒等待的生产者线程。
—–停止生产者线程和消费者线程都通过设置标志位running为false来实现。

Product.java定义产品。Producer.java模拟生产者。Consumer.java模拟消费者,Warehouse.java类模拟仓库。TestProduct.java是一个测试程序。

package com.proandcom;
public class Product {
     private  String  name;//产品名
     public Product(String name) {
           this.name = name;
     }


     public String  toString(){
           return   "Product-"+name;
     }
}

————————————————————————————

package com.proandcom;
 class Producer extends Thread {
     private  Warehouse  warehouse;//生产者存储产品的仓库
     private static int  produceName =0;//产品的名字
     private  boolean  running=false;//是否需要结束线程的标志位
     public Producer(Warehouse warehouse,String  name) {
           super(name);
           this.warehouse = warehouse;
     }

     public void start(){
           this.running=true;
           super.start();
     }

     //把需要执行的代码都写在run()方法之中
     public   void run(){
           Product   product;
           try {
                while(running){
                     //生产并且存储产品
                     product=new Product((++produceName)+"");
                     this.warehouse.storageProduct(product);
                     sleep(300);
                }
           } catch (Exception e) {
               e.printStackTrace();
           }
     }

     //停止生产者线程
     public  void  stopProducer(){
           //共享资源
           synchronized (warehouse) {
                this.running=false;//设置标志位为false
                //通知等待仓库的线程
                warehouse.notifyAll();
           }
     }

     //生产者线程是否在运行
     public boolean  isRunning(){
           return  running;
     }

}

——————————————————————————

package com.proandcom;
/*
 * 消费者,采用线程,模拟消费者行为
 */
 class Consumer  extends     Thread{
       private  Warehouse  warehouse;//消费者获取产品的仓库
       private  boolean   running  =false;//是否需要线程结束的标志位
       public Consumer(Warehouse  warehouse,String  name){
        super(name);
        this.warehouse=warehouse;
       }

       public void start(){
        this.running=true;
        super.start();
       }

       //将需要执行的代码都写在run方法中
       public  void  run(){
        Product  product;
        try {
                while(running){
                     //从仓库中获取产品
                     product=warehouse.getProduct();
                     sleep(500);
                }
           } catch (Exception e) {
                e.printStackTrace();
           }
       }

       //停止消费者线程
       public void stopConsumer(){
        //共享资源
        synchronized (warehouse) {
                //设置线程运行的标志位为false
              this.running=false;
              //通知等待仓库的线程
              warehouse.notifyAll();
           }
       }

       //消费者线程是否在运行
       public boolean  isRunning(){
        return  running;
       }
}

————————————————————————————

package com.proandcom;
/**
 * 产品的仓库类
 * 内部采用数组来表示循环队列,以存放产品。
 */
public class Warehouse {
     //仓库的容量
     private static int CAPACITY = 11;
     //仓库里的产品
     private Product[] products;

     //[front, rear)区间的产品是未被消费的
     //当前仓库中第一个未被消费的产品的下标
     private int front = 0;
     //仓库中最后一个未被消费的产品的下标加1
     private int rear = 0;
     public Warehouse(){
           this.products = new Product[CAPACITY];
     }
     public Warehouse(int capacity) {
           this();
           if (capacity > 0){
                CAPACITY = capacity + 1;
                this.products = new Product[CAPACITY];
           }
     }
     /**
      * 从仓库获取一个产品
     */
     public Product getProduct() throws InterruptedException {
           synchronized (this) {
                //标志消费者线程是否还在运行
                boolean consumerRunning = true;
                //获取当前线程
                Thread currentThread = Thread.currentThread();
                if (currentThread instanceof Consumer){
                     consumerRunning = ((Consumer)currentThread).isRunning();
                } else {
                     //非消费者不能获取产品
                     return null;
                }
                //如果仓库中没有产品,而且消费者线程还在运行,则消费者线程继续等待。
                while ((front == rear) && consumerRunning){
                     wait();
                     consumerRunning = ((Consumer)currentThread).isRunning();
                }
                //如果消费者线程已经没有运行了,则退出该方法,取消获取产品
                if (!consumerRunning){
                     return null;
                }
                //取当前未被消费的第一个产品
                Product product = products[front];
                System.out.println("Consumer[" + currentThread.getName()
                           + "] getProduct: " + product);
                //将当前未被消费产品的下标后移一位,如果到了数组末尾,则移动到首部。
                front = (front + 1 + CAPACITY) % CAPACITY;
                System.out.println("仓库中还没有被消费的产品数量:"
                           + (rear + CAPACITY - front) % CAPACITY);
                //通知其他等待线程
                notify();
                return product;
           }
     }
     /**
      * 向仓库存储一个产品
      */
     public void storageProduct(Product product) throws InterruptedException {
           synchronized (this) {
                //标志生产者线程是否在运行
                boolean producerRunning = true;
                //获取当前线程
                Thread currentThread = Thread.currentThread();
                if (currentThread instanceof Producer){
                     producerRunning = ((Producer)currentThread).isRunning();
                } else {
                     //不是生产者不能存储产品
                     return;
                }
                //如果最后一个未被消费产品与第一个未被消费的产品的下标紧挨着,
                //则说明没有存储空间,如果没有存储空间而且生产者线程还在运行,则等待仓库释放产品。
                while (((rear + 1) % CAPACITY == front) && producerRunning) {
                     wait();
                     producerRunning = ((Producer)currentThread).isRunning();
                }
                //如果生产者线程已经停止了,则停止产品的存储。
                if (!producerRunning){
                     return;
                }
                //保存参数产品到仓库
                products[rear] = product;
                System.out.println("Producer[" + Thread.currentThread().getName()
                           + "] storageProduct: " + product);
                //将rear下标循环后移一位
                rear = (rear + 1) % CAPACITY;
                System.out.println("仓库中还没有被消费的产品数量:"
                           + (rear + CAPACITY - front) % CAPACITY);
                notify();
           }
     }
}

——————————————————————

package com.proandcom;
/**
 * 测试生产者——消费者
 * 支持多个生产者和消费者
 */
public class TestProduct {
     public static void main(String[] args) {
           //建立一个仓库,容量为10
           Warehouse warehouse = new Warehouse(10);

           //建立生产者和消费者
           Producer producers1 = new Producer(warehouse, "producer-1");
           Producer producers2 = new Producer(warehouse, "producer-2");
           Producer producers3 = new Producer(warehouse, "producer-3");
           Consumer consumers1 = new Consumer(warehouse, "consumer-1");
           Consumer consumers2 = new Consumer(warehouse, "consumer-2");
           Consumer consumers3 = new Consumer(warehouse, "consumer-3");
           Consumer consumers4 = new Consumer(warehouse, "consumer-4");
           //启动生产者和消费者线程
           producers1.start();
           producers2.start();
           consumers1.start();
           producers3.start();
           consumers2.start();
           consumers3.start();
           consumers4.start();
           //让生产者消费者程序运行1600ms
           try {
                Thread.sleep(1600);
           } catch (InterruptedException e) {
                e.printStackTrace();
           }
           //停止生产者和消费者的线程
           producers1.stopProducer();
           consumers1.stopConsumer();
           producers2.stopProducer();
           consumers2.stopConsumer();
           producers3.stopProducer();
           consumers3.stopConsumer();
           consumers4.stopConsumer();
     }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值