• Java的多线程实现生产/消费模式


    Java的多线程实现生产/消费模式

    在Java的多线程中,我们经常使用某个Java对象的wait(),notify()以及notifyAll() 方法实现多线程的通讯,今天就使用Java的多线程实现生产/消费模式,需求如下:

    • 线程A ProductThread 继承Thread 实现生产数据
    • 若线程共享的数据不为NULL,则生产线程进入等待状态
    • 线程B CustomThread 继承Thread 实现消费数据(输出到控制台)
    • 当线程共享数据为NULL的时候,进入等待状态
    • 线程B 消费完数据之后,通知线程A开始生产数据

    数据共享单元

    package com.zhoutao.demo.thread.notify;
    
    public class ValueFactory {
      // 为了方便阅读代码,这里直接使用了共有的字符串类保存线程共有数据
      public static String value = null;
    }
    

    生产者

    生产者对象

    package com.zhoutao.demo.thread.notify;
    
    public class Product {
      // 线程锁对象,由主线层提供
      private String lock;
    
      public Product(String lock) {
        this.lock = lock;
      }
      
      public void setObject() throws InterruptedException {
        // 获取锁对象
        synchronized (lock) {
          // 如果数据存在, 那么生产线程进入wait
          if (ValueFactory.value != null) {
            lock.wait();
          }
          // 消费者线程通知生产者线程继续执行
          String randomStr = String.valueOf(Math.random());
          // 设置数据到线程共享对象中
          ValueFactory.value = randomStr;
          System.out.println("Put Value = " + randomStr);
          // 生产数据完成,通知消费者线程消费
          lock.notify();
        }
      }
    }
    

    生产者线程

      public class ProductThread extends Thread {
        private Product product;
    
        public ProductThread(Product product) {
          this.product = product;
        }
    
        @Override
        public void run() {
          try {
              // 不停地生产数据
            while (true) {
              product.setObject();
            }
          } catch (Exception e) {
            e.printStackTrace();
          }
        }
      }
    

    消费者

    消费者对象和生产者对象非常的类似,如果数据不存在,则等待,数据存在则消费打印,并将数据置为NULL,同时通知生产者线程生产数据

    package com.zhoutao.demo.thread.notify;
    
    import javax.xml.stream.util.XMLEventAllocator;
    import java.util.concurrent.TimeUnit;
    
    public class Custom {
    
      private String lock;
    
      public Custom(String lock) {
        this.lock = lock;
      }
    
      public void getObject() throws InterruptedException {
        synchronized (lock) {
          if (ValueFactory.value == null) {
            lock.wait();
          }
          TimeUnit.SECONDS.sleep(1);
          System.out.println("Get Value = " + ValueFactory.value);
          ValueFactory.value = null;
          lock.notify();
        }
      }
    }
    

    消费者线程

     public class CustomThread extends Thread {
        private Custom custom;
    
        public CustomThread(Custom custom) {
          this.custom = custom;
        }
    
        @Override
        public void run() {
          try {
            while (true) {
              custom.getObject();
            }
          } catch (Exception ex) {
            ex.printStackTrace();
          }
        }
      }
    

    主线程

    在生产者和消费者均创建完成后,我们尝试创建并启动两个线程,观察数据.

    public class Demo {
    
      public static void main(String[] args) {
        String lockStr = "ABC";
          
        Product product = new Product(lockStr);
        Custom custom = new Custom(lockStr);
        // 创建线程
        ProductThread pThread = new ProductThread(product);
        CustomThread cThread = new CustomThread(custom);
    
        pThread.start();
        cThread.start();
      }
    
    

    数据记录

    可以非常明显的观察到,生产者PUT数据后,通知消费者,消费者GET数据后,置空数据,再通知生产者生产数据,这样就完成了简单的生产/消费模式,当然可以使用Java的栈数据结构来实现pop() 以及push() 更加的完善。

    Put Value = 0.9451520952786396
    Get Value = 0.9451520952786396
    Put Value = 0.9103106225308949
    Get Value = 0.9103106225308949
    Put Value = 0.030296348285276054
    Get Value = 0.030296348285276054
    Put Value = 0.7746272403879736
    Get Value = 0.7746272403879736
    
  • 相关阅读:
    python函数练习题2
    python函数练习题1
    数字是否是10的整数倍
    关于循环的作业:登陆程序
    用for循环写这段代码
    while循环语句
    在CentOS8 上安装Python3
    时隔半年再写购物车程序并改进
    vue上传
    根据生日计算年龄
  • 原文地址:https://www.cnblogs.com/zhoutao825638/p/10393195.html
Copyright © 2020-2023  润新知