线程池阻塞队列详解

发布时间:2023-05-18

一、线程池阻塞队列有哪几种

线程池阻塞队列有四种类型的阻塞队列:

  • 无界队列
  • 有界队列
  • SynchronousQueue
  • DelayQueue

二、线程池阻塞队列的选择

根据业务特点,我们需要选择合适的阻塞队列类型。如果线程池的线程数是无限的,可以选择无界队列;如果线程池的线程数是有限的,可以选择有界队列或SynchronousQueue;如果需要实现延迟执行任务,可以选择DelayQueue。

三、线程池阻塞队列的概念

线程池阻塞队列是指在任务提交到线程池后,如果线程池的线程数量已经达到最大值,那么剩余的任务将会被放到一个阻塞队列中,这个队列就是线程池的阻塞队列。

四、线程池阻塞队列大小设置

线程池阻塞队列大小设置与业务需求有关。如果业务中提交的任务量较大,可以适当增加队列大小,以避免任务被拒绝。但是要注意,队列过大可能会导致OOM,因此需要在合理的范围内设置队列大小。

五、线程池阻塞队列源码

public interface BlockingQueue<E> extends Queue<E> {
    // 添加元素到队尾,如果队列已满,将会阻塞
    void put(E e) throws InterruptedException;
    // 从队头获取元素,如果队列为空,将会阻塞
    E take() throws InterruptedException;
}
public class LinkedBlockingQueue<E> extends AbstractQueue<E> implements BlockingQueue<E>, Serializable {
    // 默认队列大小为Integer.MAX_VALUE
    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }
    // 指定队列大小
    public LinkedBlockingQueue(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        this.capacity = capacity;
        last = head = new Node<E>(null);
    }
    private static class Node<E> {
        E item;
        Node<E> next;
        Node(E x) {
            item = x;
        }
    }
    // 添加元素到队尾,如果队列已满,将会阻塞
    public void put(E e) throws InterruptedException {
        if (e == null) throw new NullPointerException();
        int c = -1;
        Node<E> node = new Node<E>(e);
        final ReentrantLock putLock = this.putLock;
        final AtomicInteger count = this.count;
        putLock.lockInterruptibly();
        try {
            while (count.get() == capacity) {
                notFull.await();
            }
            enqueue(node);
            c = count.getAndIncrement();
            if (c + 1 < capacity) notFull.signal();
        } finally {
            putLock.unlock();
        }
        if (c == 0) signalNotEmpty();
    }
    // 从队头获取元素,如果队列为空,将会阻塞
    public E take() throws InterruptedException {
        E x;
        int c = -1;
        final AtomicInteger count = this.count;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lockInterruptibly();
        try {
            while (count.get() == 0) {
                notEmpty.await();
            }
            x = dequeue();
            c = count.getAndDecrement();
            if (c > 1) notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        if (c == capacity) signalNotFull();
        return x;
    }
}

六、线程池阻塞队列与拒绝策略

线程池阻塞队列与拒绝策略是相辅相成的,当任务提交到线程池后,如果线程池中的线程已经达到最大值并且线程池阻塞队列已经满了,就需要使用拒绝策略处理剩余的任务。

七、线程池阻塞队列的作用

线程池阻塞队列的作用是缓存任务,避免任务被拒绝。当线程池中的线程数量已经达到最大值后,剩余的任务就会放到阻塞队列中等待处理。

八、线程池阻塞队列导致OOM

线程池阻塞队列如果过大,可能会导致OOM。因此,在设置队列大小时需要注意避免过大。

九、线程池阻塞队列满了

当线程池阻塞队列满了,新提交的任务就会被拒绝。此时可以使用拒绝策略来处理剩余的任务。

十、线程池阻塞队列的长度选取

选择线程池阻塞队列的长度应该考虑业务需求。如果任务量很大,可以适当增加队列大小;如果希望更快的响应任务,可以适当减小队列大小。