Java多线程之线程协作
常见的线程协作方式是:生产者/消费者。
一个线程作为生产者,生产要处理数据,比如拿一个线程来生产Order,用户每下一单,此线程就生产一个Order对象。
设置一个仓库,来存放生产出来的Order对象。
一个线程作为消费者,消费|处理仓库中的Order对象(打印订单、拣货、发货)。
demo 订单处理流程
1、用一个类来封装要处理的数据
public class Order { private int id; //... public Order(int id) { this.id = id; } public int getId() { return id; } //...... }
2、仓库
import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; public class OrderStorage { //使用阻塞队列作为仓库 private BlockingQueue<Order> queues; //默认仓库容量为50 public OrderStorage() { this.queues = new LinkedBlockingQueue<>(50); } //初始化仓库容量 public OrderStorage(int capacity) { this.queues = new LinkedBlockingQueue<>(capacity); } //入库 public void push(Order order) throws InterruptedException { queues.put(order); } //出库 public Order pop() throws InterruptedException { return queues.take(); //仓库中没元素时,会阻塞当前线程,直到有元素可弹出。要不怎么叫BlockingQueue } }
java.util.concurrent包下有很多并发要使用的类,我们使用的阻塞队列就是这个包下的。concurrent 并发
队列是先进先出的,先生产的先放到仓库中,先处理。
3、生产者
public class ProducerThread extends Thread{ public static OrderStorage orderStorage = new OrderStorage(100); //仓库容量为100 @Override public void run() { int i=1; while (true){ Order order = new Order(i); try { orderStorage.push(order); //放到仓库中 System.out.println("已生产编号为"+i+"的订单"); Thread.sleep(1000); //降低速度,方便看效果 } catch (InterruptedException e) { e.printStackTrace(); } i++; } } }
容量为100,不是说只能生成50个Order,生产的同时消费者也在消费仓库中的Order。
4、消费者
public class ConsumerThread extends Thread { private OrderStorage orderStorage=ProducerThread.orderStorage; //消费者和生产者使用的要是同一个仓库 @Override public void run() { while (true){ try { Order order = orderStorage.pop(); //如果仓库中没有Order,会阻塞当前线程,直到有Order可以弹出 System.out.println("已消费|处理编号为"+order.getId()+"的订单"); Thread.sleep(1000); //降低速度,方便看效果 } catch (InterruptedException e) { e.printStackTrace(); } } } }
5、测试类
public class Test { public static void main(String[] args) { ProducerThread producerThread = new ProducerThread(); producerThread.start(); ConsumerThread consumerThread = new ConsumerThread(); consumerThread.start(); } }
6、效果
有时候一个订单,会先打印“消费”,再打印“生产”。
一个Order处理顺序一定是:生产 、入库 -> 出库、消费,要先放到仓库中才能从仓库中获取到。
只是说生产者、消费者2个线程执行sout时获取到时间片的先后不同。