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
posted @ 2019-02-17 23:08  燕归来兮  阅读(718)  评论(0编辑  收藏  举报