JUC实现生产者消费者队列

       

LinkedBlockingQueue

阻塞类:

take() 出队列头部,如果取不到,会一直阻塞

put(E)  入队列尾部,如果进不去,会一直阻塞

不报错类

offer(E) 入队列,成功true,满了返回false

poll()   出队列,没有元素返回 null

报错类

add(E) 满了报错

remove() 无元素报错

        在内存中,J.U.C提供的ThreadPoolExecutor可支持排队,通过BlockingQueue暂存还没有来得及执行的任务。

关于 LinkedBlockQueue
      这是一个阻塞的线程安全的队列,底层应该采用链表实现
      入队列:(尾部添加)
      add方法在添加元素的时候,若超出了度列的长度会直接抛出异常:
      put方法,若向队尾添加元素的时候发现队列已经满了会一直阻塞!
      offer方法在添加元素时,如果发现队列已满无法添加的话,会直接返回false。

      出队列(头部取出并移除)
      poll: 若队列为空,返回null。
      remove:若队列为空,抛出NoSuchElementException异常。
      take:若队列为空,发生阻塞,等待有元素。

      构造函数如果不接受参数,为无界队列.如果添加速度快于移除速度,则很可能OOM
      初始化的时候可增加队列长度限制,队列长度会对上述三种添加方法产生影响.
     

    protected static LinkedBlockingQueue queue = new LinkedBlockingQueue();

        用户的任务进入队列后,一般使用线程池来并发调度任务的消费。

    static final ExecutorService pool = new ThreadPoolExecutor(2, 10,
            0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(256));

关于线程池ThreadPoolExecutor

        corePoolSize:没有任务执行的时候的线程数量。相当于常驻工作组。

        maxPoolSize:如果队列已经满了,并且当前线程数量少于corePoolSize,那么就会创建新的线程。但是总线程数量不会超过maxPoolSize。

        如下代码提供了一个push方法,将用户提交的任务加入了queue队列中。该队列的构造函数没有数字,说明目前是一个无界队列。 

public class ProducerQueue ...

    protected static LinkedBlockingQueue queue = new LinkedBlockingQueue();

    static final ExecutorService pool = new ThreadPoolExecutor(2, 10,
            0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(256));


    public static void push(Object mission) {
        if (Objects.nonNull(mission)) {
            queue.add(mission);
            pool.execute(() -> VideoProducerQueue.notifies());
        }
    }

       任务入队列后,调用线程池通知消费者开始处理用户任务。

    private static void notifies() {
        while (!queue.isEmpty()) {
            Object target = queue.poll();
            if(target !=null ){
                new VideoConsumer(target).handle();
            }
        }
    }


public class VideoConsumer {
    private static final Logger LOGGER = 
                    LoggerFactory.getLogger(VideoConsumer.class);

    private Object product;

    public VideoConsumer(Object product) {
        this.product = product;
    }

    //内部也可以维护一个消费者队列

    public void handle() {
        try {
            LOGGER.info("消费对象" + product + ",入库、记录、处理....");
            Thread.sleep(3000);
        } catch (Exception ex) {
            LOGGER.error("消费" + product + "失败", ex);
        }
    }
}

      

posted @ 2022-07-17 12:12  小大宇  阅读(24)  评论(0编辑  收藏  举报