JAVA利用阻塞队列实现生产者消费者模式

思路

  1. 需要一个ServiceData类代表业务数据
  2. 需要一个DataProducer类代表生产者去生产业务数据
  3. 需要一个DataConsumer类代表消费者去消费/处理业务数据
  4. 需要一个线程池去管理生产者消费者线程

业务数据

/**
 * 业务数据
 */
public class ServiceData {
    // TODO: setter/getter省略 
    //业务数据属性
}

生产者代码

import java.util.concurrent.*;
/**
 * 生产者
 */
public class DataProducer implements Runnable {

    private BlockingQueue<ServiceData> queue;
    
    public DataProducer(BlockingQueue<ServiceData> queue) {
        this.queue = queue;
    }
    
    @Override
    public void run() {
        //模拟生产十万个数据
        for (int i = 0; i < 100000; i++) {
            try {
                ServiceData data = new ServiceData();
                //todo 生产数据过程
                queue.put(data);
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

消费者代码

import java.util.concurrent.*;
/**
 * 消费者
 */
public class DataConsumer implements Runnable {

    private BlockingQueue<ServiceData> queue;
    
    public DataConsumer(BlockingQueue<ServiceData> queue) {
        this.queue = queue;
    }

    /**
     * 当前任务是否完成
     */
    private boolean finished;
    public boolean isFinished() {
        return finished;
    }

    /**
     * 判断所有消费者都完成任务
     * @param consumers
     * @return
     */
    public static boolean isAllFinished(DataConsumer... consumers) {
        for (DataConsumer consumer : consumers) {
            if (!consumer.isFinished()) {
                return false;
            }
        }
        return true;
    }
    
    @Override
    public void run() {
        //不停消费数据,没有数据时阻塞
        while (true) {
            try {
                ServiceData data = queue.take();
                finished = false;
                //todo 消费数据过程
            }catch (Exception e) {
                e.printStackTrace();
            }finally {
                finished = true;
            }
        }
    }
}

线程池

import java.util.concurrent.*;

public class Test {
    public static void main(String[] args) {
        //创建一个有三个固定线程的线程池
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        //创建任务队列
        BlockingQueue<PdfUrl> queue = new LinkedBlockingQueue<>();
        //创建一个生产者
        DataProducer producer1 = new DataProducer(queue);
        //创建两个消费者
        DataConsumer consumer1 = new DataConsumer(queue);
        DataConsumer consumer2 = new DataConsumer(queue);
        //启动任务
        executorService.execute(producer1);
        executorService.execute(consumer1);
        executorService.execute(consumer2);
        //生产者生产完成后,队列空了并且消费完成,则结束
        while (true) {
            if (queue.isEmpty() && DataConsumer.isAllFinished(consumer1,consumer2)) {
                break;
            }
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //关闭线程池,立即stop线程
        threadPool.shutdownNow();
    }
}
posted @ 2022-03-01 11:13  小小爬虫  阅读(234)  评论(0编辑  收藏  举报