• Java并发-生产者消费者实现


    生产者与消费者模型介绍

    定义生产者消费者模式是一个十分经典的多线程并发协作的模式。

    意义:弄懂生产者消费者问题能够让我们对并发编程的理解加深。

    介绍:所谓生产者 - 消费者问题,实际上主要是包含了两类线程,一种是生产者线程用于生产数据,另一种是消费者线程用于消费数据,为了解耦生产者和消费者的关系,通常会采用共享的数据区域。

    共享的数据区域就像是一个仓库,生产者生产数据之后直接放置在共享数据区中,并不需要关心消费者的行为。而消费者只需要从共享数据区中去获取数据,就不再需要关心生产者的行为。

    生产者与消费者实现

    场景设计

    • 创建一个工厂类 ProductFactory,该类包含两个方法,produce 生产方法和 consume 消费方法;
    • 对于 produce 方法,当没有库存或者库存达到 10 时,停止生产。为了更便于观察结果,每生产一个产品,sleep 3秒;
    • 对于 consume 方法,只要有库存就进行消费。为了更便于观察结果,每消费一个产品,sleep 3秒;
    • 库存使用 LinkedList 进行实现,此时 LinkedList 即共享数据内存
    • 创建一个 Producer 生产者类,用于调用 ProductFactory 的 produce 方法。生产过程中,要对每个产品从 0 开始进行编号;
    • 创建一个 Consumer 消费者类,用于调用 ProductFactory 的 consume 方法;
    • 创建一个测试类,main 函数中创建 2 个生产者和 3 个消费者,运行程序进行结果观察。

    ProductFactory.class

    1. package jvm.juc.proAndcom;
    2. import java.util.LinkedList;
    3. public class ProductFactory {
    4. private volatile LinkedList products; //根据需求定义库存,用 LinkedList 实现
    5. private int capacity = 10; // 根据需求:定义最大库存 10
    6. public ProductFactory() {
    7. products = new LinkedList();
    8. }
    9. // 根据需求:produce 方法创建
    10. public synchronized void produce(String product) {
    11. while (capacity == products.size()) { //根据需求:如果达到 10 库存,停止生产
    12. try {
    13. System.out.println("警告:线程("+Thread.currentThread().getName() + ")准备生产产品,但产品池已满");
    14. wait();
    15. } catch (InterruptedException e) {
    16. e.printStackTrace();
    17. }
    18. }
    19. products.add(product); //如果没有到 10 库存,进行产品添加
    20. try {
    21. Thread.sleep(1000); //根据需求为了便于观察结果,每生产一个产品,sleep 5000 ms
    22. } catch (InterruptedException e) {
    23. e.printStackTrace();
    24. }
    25. System.out.println("线程("+Thread.currentThread().getName() + ")生产了一件产品:" + product+";当前剩余商品"+products.size()+"个");
    26. notify(); //生产了产品,通知消费者线程从 wait 状态唤醒,进行消费
    27. }
    28. // 根据需求:consume 方法创建
    29. public synchronized String consume() {
    30. while (products.size()==0) { //根据需求:没有库存消费者进入wait状态
    31. try {
    32. System.out.println("警告:线程("+Thread.currentThread().getName() + ")准备消费产品,但当前没有产品");
    33. wait(); //库存为 0 ,无法消费,进入 wait ,等待生产者线程唤醒
    34. } catch (InterruptedException e) {
    35. e.printStackTrace();
    36. }
    37. }
    38. String product = products.remove(0) ; //如果有库存则消费,并移除消费掉的产品
    39. try {
    40. Thread.sleep(1000);//根据需求为了便于观察结果,每消费一个产品,sleep 5000 ms
    41. } catch (InterruptedException e) {
    42. e.printStackTrace();
    43. }
    44. System.out.println("线程("+Thread.currentThread().getName() + ")消费了一件产品:" + product+";当前剩余商品"+products.size()+"个");
    45. notify();// 通知生产者继续生产
    46. return product;
    47. }
    48. }

    Consumer.Class

    1. package jvm.juc.proAndcom;
    2. public class Consumer implements Runnable{
    3. private ProductFactory factory;
    4. public Consumer(ProductFactory productFactory) {
    5. factory = productFactory;
    6. }
    7. @Override
    8. public void run() {
    9. while (true) {
    10. String consume = factory.consume();
    11. }
    12. }
    13. }

    Producer.class

    1. package jvm.juc.proAndcom;
    2. public class Producer implements Runnable{
    3. private ProductFactory factory;
    4. public Producer(ProductFactory productFactory) {
    5. this.factory = productFactory;
    6. }
    7. @Override
    8. public void run() {
    9. int i = 0;
    10. while (true) {
    11. factory.produce(String.valueOf(i));
    12. i++;
    13. }
    14. }
    15. }

    Test.class

    1. package jvm.juc.proAndcom;
    2. import internet.c1.Factory;
    3. public class Test extends Thread{
    4. public static void main(String[] args) {
    5. ProductFactory factory = new ProductFactory();
    6. new Thread(new Producer(factory),"一号生产者").start();
    7. new Thread(new Producer(factory),"二号生产者").start();
    8. new Thread(new Consumer(factory),"一号消费者").start();
    9. new Thread(new Consumer(factory),"二号消费者").start();
    10. new Thread(new Consumer(factory),"三号消费者").start();
    11. }
    12. }

  • 相关阅读:
    业务数据分析-常见业务指标
    最详细的专利申请教程,教你如何申请专利
    2023年江西省职业院校技能竞赛“网络安全”赛项样题
    在一台电脑上安装多个python版本(小白教程)
    灌水时间:树莓派4+Lakka做怀旧游戏机
    《Redis篇》Another Redis DeskTop Manager 超详细安装教程
    多站点用户数据同步实现
    景联文科技:驾驭数据浪潮,赋能AI产业——全球领先的数据标注解决方案供应商
    (02)Cartographer源码无死角解析-(25) 阻塞队列BlockingQueue,与OrderedMultiQueue成员函数
    深度学习:维度灾难(Curse Of Dimensionality)
  • 原文地址:https://blog.csdn.net/abc123mma/article/details/128061802