JUC并发编程 阻塞队列

14 阅读25分钟

阻塞队列

1. 阻塞队列概述

1.1 什么是阻塞队列

阻塞队列(BlockingQueue)是Java并发包中的重要组件,它在普通队列的基础上增加了阻塞功能:

  • 生产者阻塞:当队列满时,生产者线程会被阻塞,直到队列有空间
  • 消费者阻塞:当队列空时,消费者线程会被阻塞,直到队列有元素

1.2 阻塞队列的核心特性

graph TB
    A[阻塞队列核心特性] --> B[线程安全]
    A --> C[阻塞机制]
    A --> D[容量控制]
    A --> E[多种操作模式]
    
    B --> B1[内部使用锁机制]
    B --> B2[原子操作保证]
    
    C --> C1[put/take阻塞]
    C --> C2[offer/poll超时]
    
    D --> D1[有界队列]
    D --> D2[无界队列]
    
    E --> E1[抛异常模式]
    E --> E2[返回特殊值]
    E --> E3[阻塞模式]
    E --> E4[超时模式]

1.3 Java中的阻塞队列实现

classDiagram
    class BlockingQueue {
        <<interface>>
        +put(E e)
        +take() E
        +offer(E e) boolean
        +poll() E
        +offer(E e, long timeout, TimeUnit unit) boolean
        +poll(long timeout, TimeUnit unit) E
        +remainingCapacity() int
        +drainTo(Collection c) int
    }
    
    class BlockingDeque {
        <<interface>>
        +putFirst(E e)
        +putLast(E e)
        +takeFirst() E
        +takeLast() E
        +offerFirst(E e, long timeout, TimeUnit unit) boolean
        +offerLast(E e, long timeout, TimeUnit unit) boolean
        +pollFirst(long timeout, TimeUnit unit) E
        +pollLast(long timeout, TimeUnit unit) E
    }
    
    class ArrayBlockingQueue {
        -Object[] items
        -int takeIndex
        -int putIndex
        -int count
        -ReentrantLock lock
        -Condition notEmpty
        -Condition notFull
    }
    
    class LinkedBlockingQueue {
        -Node~E~ head
        -Node~E~ last
        -AtomicInteger count
        -ReentrantLock takeLock
        -ReentrantLock putLock
        -Condition notEmpty
        -Condition notFull
    }
    
    class PriorityBlockingQueue {
        -Object[] queue
        -int size
        -Comparator~E~ comparator
        -ReentrantLock lock
        -Condition notEmpty
    }
    
    class SynchronousQueue {
        -Transferer~E~ transferer
    }
    
    class LinkedBlockingDeque {
        -Node~E~ first
        -Node~E~ last
        -int count
        -int capacity
        -ReentrantLock lock
        -Condition notEmpty
        -Condition notFull
    }
    
    BlockingQueue <|-- BlockingDeque
    BlockingQueue <|.. ArrayBlockingQueue
    BlockingQueue <|.. LinkedBlockingQueue
    BlockingQueue <|.. PriorityBlockingQueue
    BlockingQueue <|.. SynchronousQueue
    BlockingDeque <|.. LinkedBlockingDeque

2. BlockingQueue 接口分析

2.1 接口定义与核心方法

从项目源码 BlockingQueue.java 中可以看到接口的完整定义:

/**
 * 阻塞队列接口 - 扩展了Queue接口,增加了阻塞操作
 * 支持四种操作模式:抛异常、返回特殊值、阻塞、超时
 */
public interface BlockingQueue<E> extends Queue<E> {
    
    // ========== 插入操作 ==========
    
    /**
     * 立即插入元素,成功返回true,容量不足抛IllegalStateException
     * 对应操作模式:抛异常
     */
    boolean add(E e);
    
    /**
     * 立即插入元素,成功返回true,容量不足返回false
     * 对应操作模式:返回特殊值
     */
    boolean offer(E e);
    
    /**
     * 插入元素,必要时等待空间可用
     * 对应操作模式:阻塞
     */
    void put(E e) throws InterruptedException;
    
    /**
     * 插入元素,等待指定时间,超时返回false
     * 对应操作模式:超时
     */
    boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException;
    
    // ========== 移除操作 ==========
    
    /**
     * 移除并返回队头元素,必要时等待元素可用
     * 对应操作模式:阻塞
     */
    E take() throws InterruptedException;
    
    /**
     * 移除并返回队头元素,等待指定时间,超时返回null
     * 对应操作模式:超时
     */
    E poll(long timeout, TimeUnit unit) throws InterruptedException;
    
    // ========== 检查操作 ==========
    
    /**
     * 返回队列剩余容量,无限制返回Integer.MAX_VALUE
     */
    int remainingCapacity();
    
    /**
     * 移除指定元素的一个实例(如果存在)
     */
    boolean remove(Object o);
    
    /**
     * 检查队列是否包含指定元素
     */
    boolean contains(Object o);
    
    // ========== 批量操作 ==========
    
    /**
     * 移除所有可用元素并添加到指定集合
     * 比重复调用poll()更高效
     */
    int drainTo(Collection<? super E> c);
    
    /**
     * 移除最多指定数量的元素并添加到指定集合
     */
    int drainTo(Collection<? super E> c, int maxElements);
}

2.2 四种操作模式对比

graph TB
    subgraph "插入操作"
        A1[add - 抛异常] --> A1R[成功:true<br/>失败:IllegalStateException]
        A2[offer - 特殊值] --> A2R[成功:true<br/>失败:false]
        A3[put - 阻塞] --> A3R[成功:void<br/>失败:等待或InterruptedException]
        A4[offer超时 - 超时] --> A4R[成功:true<br/>超时:false<br/>中断:InterruptedException]
    end
    
    subgraph "移除操作"
        B1[remove - 抛异常] --> B1R[成功:元素<br/>失败:NoSuchElementException]
        B2[poll - 特殊值] --> B2R[成功:元素<br/>失败:null]
        B3[take - 阻塞] --> B3R[成功:元素<br/>失败:等待或InterruptedException]
        B4[poll超时 - 超时] --> B4R[成功:元素<br/>超时:null<br/>中断:InterruptedException]
    end

2.3 生产者-消费者模式示例

sequenceDiagram
    participant P as 生产者线程
    participant Q as BlockingQueue
    participant C as 消费者线程
    
    Note over P,C: 队列为空时的阻塞行为
    C->>Q: take() - 尝试获取元素
    Q-->>C: 阻塞等待...
    
    P->>Q: put(element) - 插入元素
    Q->>Q: 唤醒等待的消费者
    Q-->>C: 返回元素
    
    Note over P,C: 队列满时的阻塞行为
    P->>Q: put(element) - 尝试插入
    Q-->>P: 阻塞等待...
    
    C->>Q: take() - 获取元素
    Q->>Q: 唤醒等待的生产者
     Q-->>P: 插入成功

3. BlockingDeque 接口分析

3.1 双端阻塞队列特性

从项目源码 BlockingDeque.java 中可以看到双端阻塞队列的完整定义:

/**
 * 双端阻塞队列接口 - 同时继承BlockingQueue和Deque
 * 支持在队列两端进行阻塞操作
 */
public interface BlockingDeque<E> extends BlockingQueue<E>, Deque<E> {
    
    // ========== 队头操作 ==========
    
    /**
     * 在队头插入元素,必要时等待空间可用
     */
    void putFirst(E e) throws InterruptedException;
    
    /**
     * 在队头插入元素,等待指定时间
     */
    boolean offerFirst(E e, long timeout, TimeUnit unit) throws InterruptedException;
    
    /**
     * 从队头移除元素,必要时等待元素可用
     */
    E takeFirst() throws InterruptedException;
    
    /**
     * 从队头移除元素,等待指定时间
     */
    E pollFirst(long timeout, TimeUnit unit) throws InterruptedException;
    
    // ========== 队尾操作 ==========
    
    /**
     * 在队尾插入元素,必要时等待空间可用
     */
    void putLast(E e) throws InterruptedException;
    
    /**
     * 在队尾插入元素,等待指定时间
     */
    boolean offerLast(E e, long timeout, TimeUnit unit) throws InterruptedException;
    
    /**
     * 从队尾移除元素,必要时等待元素可用
     */
    E takeLast() throws InterruptedException;
    
    /**
     * 从队尾移除元素,等待指定时间
     */
    E pollLast(long timeout, TimeUnit unit) throws InterruptedException;
}

3.2 BlockingDeque与BlockingQueue方法映射

graph LR
    subgraph "BlockingQueue方法"
        BQ1[add/offer/put]
        BQ2[remove/poll/take]
        BQ3[element/peek]
    end
    
    subgraph "等价的BlockingDeque方法"
        BD1[addLast/offerLast/putLast]
        BD2[removeFirst/pollFirst/takeFirst]
        BD3[getFirst/peekFirst]
    end
    
    BQ1 --> BD1
    BQ2 --> BD2
    BQ3 --> BD3

4. ArrayBlockingQueue 源码解析

4.1 核心数据结构

从项目源码 ArrayBlockingQueue.java 中可以看到其核心实现:

/**
 * 基于数组的有界阻塞队列
 * 特点:FIFO顺序、固定容量、可选公平性
 */
public class ArrayBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
    
    // ========== 核心字段 ==========
    
    /** 存储队列元素的数组 - 固定大小 */
    final Object[] items;
    
    /** 下次take、poll、peek或remove操作的索引位置 */
    int takeIndex;
    
    /** 下次put、offer或add操作的索引位置 */
    int putIndex;
    
    /** 队列中元素的数量 */
    int count;
    
    // ========== 并发控制 ==========
    
    /** 保护所有访问的主锁 */
    final ReentrantLock lock;
    
    /** 等待take操作的条件队列 - 队列非空条件 */
    private final Condition notEmpty;
    
    /** 等待put操作的条件队列 - 队列非满条件 */
    private final Condition notFull;
    
    /** 当前活跃迭代器的共享状态 */
    transient Itrs itrs;
}

4.2 构造方法分析

/**
 * 构造指定容量的ArrayBlockingQueue
 * @param capacity 队列容量,必须大于0
 * @param fair 是否使用公平锁,默认false(非公平)
 */
public ArrayBlockingQueue(int capacity, boolean fair) {
    if (capacity <= 0)
        throw new IllegalArgumentException();
    
    // 初始化固定大小的数组
    this.items = new Object[capacity];
    
    // 创建可重入锁,支持公平/非公平模式
    lock = new ReentrantLock(fair);
    
    // 基于锁创建条件队列
    notEmpty = lock.newCondition();  // 队列非空条件
    notFull = lock.newCondition();   // 队列非满条件
}

/**
 * 构造指定容量和初始元素的ArrayBlockingQueue
 */
public ArrayBlockingQueue(int capacity, boolean fair, Collection<? extends E> c) {
    this(capacity, fair);
    
    final ReentrantLock lock = this.lock;
    lock.lock(); // 确保可见性,不是为了互斥
    try {
        final Object[] items = this.items;
        int i = 0;
        try {
            // 将集合中的元素复制到数组中
            for (E e : c)
                items[i++] = Objects.requireNonNull(e);
        } catch (ArrayIndexOutOfBoundsException ex) {
            throw new IllegalArgumentException();
        }
        count = i;      // 设置元素数量
        putIndex = (i == capacity) ? 0 : i;  // 设置下次插入位置
    } finally {
        lock.unlock();
    }
}

4.3 核心操作方法

4.3.1 入队操作 - put方法
/**
 * 阻塞式插入元素 - 队列满时等待
 */
public void put(E e) throws InterruptedException {
    Objects.requireNonNull(e);  // 不允许null元素
    
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();   // 可中断的锁获取
    try {
        // 队列满时,在notFull条件上等待
        while (count == items.length)
            notFull.await();
        
        enqueue(e);  // 执行入队操作
    } finally {
        lock.unlock();
    }
}

/**
 * 非阻塞式插入元素 - 队列满时返回false
 */
public boolean offer(E e) {
    Objects.requireNonNull(e);
    
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        if (count == items.length)
            return false;  // 队列满,直接返回false
        else {
            enqueue(e);
            return true;
        }
    } finally {
        lock.unlock();
    }
}

/**
 * 超时插入元素 - 在指定时间内等待空间
 */
public boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException {
    Objects.requireNonNull(e);
    long nanos = unit.toNanos(timeout);
    
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == items.length) {
            if (nanos <= 0L)
                return false;  // 超时返回false
            
            // 在notFull条件上等待指定时间
            nanos = notFull.awaitNanos(nanos);
        }
        enqueue(e);
        return true;
    } finally {
        lock.unlock();
    }
}
4.3.2 出队操作 - take方法
/**
 * 阻塞式获取元素 - 队列空时等待
 */
public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        // 队列空时,在notEmpty条件上等待
        while (count == 0)
            notEmpty.await();
        
        return dequeue();  // 执行出队操作
    } finally {
        lock.unlock();
    }
}

/**
 * 非阻塞式获取元素 - 队列空时返回null
 */
public E poll() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        return (count == 0) ? null : dequeue();
    } finally {
        lock.unlock();
    }
}

/**
 * 超时获取元素 - 在指定时间内等待元素
 */
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
    long nanos = unit.toNanos(timeout);
    
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    try {
        while (count == 0) {
            if (nanos <= 0L)
                return null;  // 超时返回null
            
            // 在notEmpty条件上等待指定时间
            nanos = notEmpty.awaitNanos(nanos);
        }
        return dequeue();
    } finally {
        lock.unlock();
    }
}

4.4 内部辅助方法

/**
 * 循环递增索引 - 实现环形数组
 */
final int inc(int i) {
    return (++i == items.length) ? 0 : i;
}

/**
 * 循环递减索引
 */
final int dec(int i) {
    return ((i == 0) ? items.length : i) - 1;
}

/**
 * 入队操作 - 在putIndex位置插入元素
 * 调用前必须持有锁
 */
private void enqueue(E e) {
    final Object[] items = this.items;
    items[putIndex] = e;           // 在putIndex位置放入元素
    
    if (++putIndex == items.length)  // 更新putIndex,实现环形
        putIndex = 0;
    
    count++;                       // 增加元素计数
    notEmpty.signal();            // 唤醒等待获取元素的线程
}

/**
 * 出队操作 - 从takeIndex位置移除元素
 * 调用前必须持有锁
 */
private E dequeue() {
    final Object[] items = this.items;
    @SuppressWarnings("unchecked")
    E e = (E) items[takeIndex];    // 获取takeIndex位置的元素
    
    items[takeIndex] = null;       // 清空引用,帮助GC
    
    if (++takeIndex == items.length)  // 更新takeIndex,实现环形
        takeIndex = 0;
    
    count--;                       // 减少元素计数
    
    if (itrs != null)
        itrs.elementDequeued();    // 通知迭代器元素被移除
    
    notFull.signal();             // 唤醒等待插入元素的线程
    return e;
}

4.5 ArrayBlockingQueue内存结构图

flowchart TB
    subgraph ABQ ["ArrayBlockingQueue内存结构"]
        A[ArrayBlockingQueue实例]
        
        subgraph Fields ["核心字段"]
            B["Object[] items<br/>存储数组"]
            C["int takeIndex<br/>取元素索引"]
            D["int putIndex<br/>放元素索引"]
            E["int count<br/>元素数量"]
        end
        
        subgraph Locks ["并发控制"]
            F["ReentrantLock lock<br/>主锁"]
            G["Condition notEmpty<br/>非空条件"]
            H["Condition notFull<br/>非满条件"]
        end
        
        subgraph Array ["数组状态示例"]
            B1["[0] element1"]
            B2["[1] element2"]
            B3["[2] null"]
            B4["[3] null"]
        end
        
        A --> Fields
        A --> Locks
        B -.-> Array
        
        C -.-> |"指向位置 0"| B1
        D -.-> |"指向位置 2"| B3
        E -.-> |"当前数量: 2"| Array
    end

4.6 环形数组工作原理

sequenceDiagram
    participant T as 线程
    participant A as ArrayBlockingQueue
    participant Arr as items数组
    
    Note over T,Arr: 初始状态:takeIndex=0, putIndex=0, count=0
    
    T->>A: put("A")
    A->>Arr: items[0] = "A"
    A->>A: putIndex = 1, count = 1
    
    T->>A: put("B")
    A->>Arr: items[1] = "B"
    A->>A: putIndex = 2, count = 2
    
    T->>A: take()
    A->>Arr: 获取items[0] = "A"
    A->>Arr: items[0] = null
    A->>A: takeIndex = 1, count = 1
    
    Note over T,Arr: 当putIndex到达数组末尾时,重置为0(环形)
    
    T->>A: put("C") [假设数组长度为3]
     A->>Arr: items[2] = "C"
     A->>A: putIndex = 0 (环形重置), count = 2

4.7 ArrayBlockingQueue特性总结

  • 有界队列:容量固定,防止内存溢出
  • FIFO顺序:先进先出,保证公平性
  • 单锁设计:所有操作共享一个锁,简单但可能成为瓶颈
  • 环形数组:高效的内存利用,避免数组移动
  • 条件队列:使用Condition实现精确的线程唤醒
  • 可选公平性:支持公平/非公平锁模式

5. LinkedBlockingQueue 源码解析

5.1 核心数据结构

从项目源码 LinkedBlockingQueue.java 中可以看到其基于链表的实现:

/**
 * 基于链表的可选有界阻塞队列
 * 特点:FIFO顺序、可选容量限制、双锁设计
 */
public class LinkedBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
    
    // ========== 节点定义 ==========
    
    /**
     * 链表节点 - 单向链表结构
     */
    static class Node<E> {
        E item;          // 节点存储的元素
        Node<E> next;    // 指向下一个节点的指针
        
        Node(E x) { item = x; }
    }
    
    // ========== 核心字段 ==========
    
    /** 队列容量,默认Integer.MAX_VALUE */
    private final int capacity;
    
    /** 当前队列中的元素数量 - 使用原子整数 */
    private final AtomicInteger count = new AtomicInteger();
    
    /** 队列头节点 - 虚拟头节点,不存储实际数据 */
    transient Node<E> head;
    
    /** 队列尾节点 - 指向最后一个实际节点 */
    private transient Node<E> last;
    
    // ========== 双锁设计 ==========
    
    /** take操作的锁 - 保护头部操作 */
    private final ReentrantLock takeLock = new ReentrantLock();
    
    /** 等待take操作的条件队列 */
    private final Condition notEmpty = takeLock.newCondition();
    
    /** put操作的锁 - 保护尾部操作 */
    private final ReentrantLock putLock = new ReentrantLock();
    
    /** 等待put操作的条件队列 */
    private final Condition notFull = putLock.newCondition();
}

5.2 构造方法分析

/**
 * 构造无界LinkedBlockingQueue(容量为Integer.MAX_VALUE)
 */
public LinkedBlockingQueue() {
    this(Integer.MAX_VALUE);
}

/**
 * 构造指定容量的LinkedBlockingQueue
 */
public LinkedBlockingQueue(int capacity) {
    if (capacity <= 0) throw new IllegalArgumentException();
    
    this.capacity = capacity;
    
    // 初始化虚拟头节点
    last = head = new Node<E>(null);
}

/**
 * 构造包含指定集合元素的LinkedBlockingQueue
 */
public LinkedBlockingQueue(Collection<? extends E> c) {
    this(Integer.MAX_VALUE);
    
    final ReentrantLock putLock = this.putLock;
    putLock.lock(); // 确保可见性
    try {
        int n = 0;
        for (E e : c) {
            if (e == null)
                throw new NullPointerException();
            
            if (n == capacity)
                throw new IllegalStateException("Queue full");
            
            enqueue(new Node<E>(e));
            ++n;
        }
        count.set(n);
    } finally {
        putLock.unlock();
    }
}

5.3 双锁机制核心操作

5.3.1 入队操作 - put方法
/**
 * 阻塞式插入元素 - 使用putLock
 */
public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    
    final int c;
    final 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();      // 原子递增计数
        
        // 如果队列还有空间,唤醒其他等待put的线程
        if (c + 1 < capacity)
            notFull.signal();
    } finally {
        putLock.unlock();
    }
    
    // 如果这是第一个元素,唤醒等待take的线程
    if (c == 0)
        signalNotEmpty();
}

/**
 * 入队操作 - 在链表尾部添加节点
 * 调用前必须持有putLock
 */
private void enqueue(Node<E> node) {
    // 将新节点链接到链表尾部
    last = last.next = node;
}

/**
 * 唤醒等待take的线程
 * 需要获取takeLock来安全地访问notEmpty条件
 */
private void signalNotEmpty() {
    final ReentrantLock takeLock = this.takeLock;
    takeLock.lock();
    try {
        notEmpty.signal();
    } finally {
        takeLock.unlock();
    }
}
5.3.2 出队操作 - take方法
/**
 * 阻塞式获取元素 - 使用takeLock
 */
public E take() throws InterruptedException {
    final E x;
    final int c;
    final AtomicInteger count = this.count;
    final ReentrantLock takeLock = this.takeLock;
    
    takeLock.lockInterruptibly();
    try {
        // 队列空时等待
        while (count.get() == 0) {
            notEmpty.await();
        }
        
        x = dequeue();                    // 执行出队
        c = count.getAndDecrement();      // 原子递减计数
        
        // 如果队列还有元素,唤醒其他等待take的线程
        if (c > 1)
            notEmpty.signal();
    } finally {
        takeLock.unlock();
    }
    
    // 如果队列有空间了,唤醒等待put的线程
    if (c == capacity)
        signalNotFull();
    
    return x;
}

/**
 * 出队操作 - 从链表头部移除节点
 * 调用前必须持有takeLock
 */
private E dequeue() {
    Node<E> h = head;           // 获取虚拟头节点
    Node<E> first = h.next;     // 获取第一个实际节点
    h.next = h;                 // 帮助GC
    head = first;               // 更新头节点
    E x = first.item;           // 获取元素
    first.item = null;          // 清空引用
    return x;
}

/**
 * 唤醒等待put的线程
 * 需要获取putLock来安全地访问notFull条件
 */
private void signalNotFull() {
    final ReentrantLock putLock = this.putLock;
    putLock.lock();
    try {
        notFull.signal();
    } finally {
        putLock.unlock();
    }
}

5.4 LinkedBlockingQueue内存结构图

graph TB
    subgraph "LinkedBlockingQueue内存结构"
        A[LinkedBlockingQueue] --> B[Node head - 虚拟头节点]
        A --> C[Node last - 尾节点]
        A --> D[AtomicInteger count]
        A --> E[ReentrantLock takeLock]
        A --> F[ReentrantLock putLock]
        A --> G[Condition notEmpty]
        A --> H[Condition notFull]
        
        B --> B1["item: null<br/>next: →"]
        B1 --> B2["item: element1<br/>next: →"]
        B2 --> B3["item: element2<br/>next: →"]
        B3 --> B4["item: element3<br/>next: null"]
        
        C --> B4
        
        D --> D1["当前元素数量: 3"]
        E --> E1["保护头部操作"]
        F --> F1["保护尾部操作"]
        G --> G1["队列非空条件"]
        H --> H1["队列非满条件"]
    end

5.5 双锁机制优势分析

sequenceDiagram
    participant P1 as 生产者线程1
    participant P2 as 生产者线程2
    participant Q as LinkedBlockingQueue
    participant C1 as 消费者线程1
    participant C2 as 消费者线程2
    
    Note over P1,C2: 双锁允许并发的put和take操作
    
    par 并发put操作
        P1->>Q: put("A") - 获取putLock
        Q->>Q: enqueue at tail
    and
        P2->>Q: put("B") - 等待putLock
    and 并发take操作
        C1->>Q: take() - 获取takeLock
        Q->>Q: dequeue from head
    and
        C2->>Q: take() - 等待takeLock
    end
    
    Note over P1,C2: put和take可以同时进行,提高并发性

5.6 LinkedBlockingQueue特性总结

  • 可选有界:可以指定容量,默认无界(Integer.MAX_VALUE)
  • 双锁设计:putLock和takeLock分离,提高并发性
  • 链表结构:动态内存分配,适合大容量场景
  • 原子计数:使用AtomicInteger保证count的线程安全
  • 虚拟头节点:简化链表操作,避免特殊情况处理
  • FIFO顺序:严格的先进先出顺序

6. PriorityBlockingQueue 源码解析

6.1 核心数据结构

从项目源码 PriorityBlockingQueue.java 中可以看到其基于堆的实现:

/**
 * 基于优先级堆的无界阻塞队列
 * 特点:优先级排序、无界容量、单锁设计
 */
public class PriorityBlockingQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
    
    // ========== 核心字段 ==========
    
    /** 默认初始容量 */
    private static final int DEFAULT_INITIAL_CAPACITY = 11;
    
    /** 最大数组大小 */
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;
    
    /** 存储队列元素的数组 - 二叉堆结构 */
    private transient Object[] queue;
    
    /** 队列中元素的数量 */
    private transient int size;
    
    /** 元素比较器,null表示使用自然排序 */
    private transient Comparator<? super E> comparator;
    
    /** 保护所有公共操作的锁 */
    private final ReentrantLock lock;
    
    /** 等待take操作的条件队列 */
    private final Condition notEmpty;
    
    /** 
     * 用于分配的自旋锁(通过CAS操作)
     * 在扩容时使用,避免多个线程同时扩容
     */
    private transient volatile int allocationSpinLock;
    
    /** 
     * 普通PriorityQueue,用于序列化/反序列化
     * 仅在序列化时使用
     */
    private PriorityQueue<E> q;
}

6.2 构造方法分析

/**
 * 构造默认容量的PriorityBlockingQueue
 */
public PriorityBlockingQueue() {
    this(DEFAULT_INITIAL_CAPACITY, null);
}

/**
 * 构造指定初始容量的PriorityBlockingQueue
 */
public PriorityBlockingQueue(int initialCapacity) {
    this(initialCapacity, null);
}

/**
 * 构造指定初始容量和比较器的PriorityBlockingQueue
 */
public PriorityBlockingQueue(int initialCapacity,
                             Comparator<? super E> comparator) {
    if (initialCapacity < 1)
        throw new IllegalArgumentException();
    
    this.lock = new ReentrantLock();
    this.notEmpty = lock.newCondition();
    this.comparator = comparator;
    this.queue = new Object[initialCapacity];
}

/**
 * 构造包含指定集合元素的PriorityBlockingQueue
 */
public PriorityBlockingQueue(Collection<? extends E> c) {
    this.lock = new ReentrantLock();
    this.notEmpty = lock.newCondition();
    
    boolean heapify = true; // 是否需要堆化
    boolean screen = true;  // 是否需要检查null
    
    if (c instanceof SortedSet<?>) {
        SortedSet<? extends E> ss = (SortedSet<? extends E>) c;
        this.comparator = (Comparator<? super E>) ss.comparator();
        heapify = false;
    }
    else if (c instanceof PriorityBlockingQueue<?>) {
        PriorityBlockingQueue<? extends E> pq =
            (PriorityBlockingQueue<? extends E>) c;
        this.comparator = (Comparator<? super E>) pq.comparator();
        screen = false;
        if (pq.getClass() == PriorityBlockingQueue.class)
            heapify = false;
    }
    
    Object[] es = c.toArray();
    int n = es.length;
    
    // 检查null元素
    if (screen && (n == 1 || this.comparator != null)) {
        for (Object e : es) {
            if (e == null)
                throw new NullPointerException();
        }
    }
    
    this.queue = ensureNonEmpty(es);
    this.size = n;
    
    // 如果需要,进行堆化
    if (heapify)
        heapify();
}

6.3 核心操作方法

6.3.1 入队操作 - put方法
/**
 * 插入元素 - 由于是无界队列,put永远不会阻塞
 */
public void put(E e) {
    offer(e); // 直接调用offer,因为无界队列不会满
}

/**
 * 非阻塞插入元素
 */
public boolean offer(E e) {
    if (e == null)
        throw new NullPointerException();
    
    final ReentrantLock lock = this.lock;
    lock.lock();
    int n, cap;
    Object[] es;
    
    // 检查是否需要扩容
    while ((n = size) >= (cap = (es = queue).length))
        tryGrow(es, cap);
    
    try {
        final Comparator<? super E> cmp;
        if ((cmp = comparator) == null)
            siftUpComparable(n, e, es);    // 使用自然排序上浮
        else
            siftUpUsingComparator(n, e, es, cmp);  // 使用比较器上浮
        
        size = n + 1;
        notEmpty.signal();  // 唤醒等待的消费者
    } finally {
        lock.unlock();
    }
    return true;
}

/**
 * 使用自然排序进行上浮操作
 * 维护最小堆性质
 */
private static <T> void siftUpComparable(int k, T x, Object[] es) {
    Comparable<? super T> key = (Comparable<? super T>) x;
    
    while (k > 0) {
        int parent = (k - 1) >>> 1;  // 父节点索引
        Object e = es[parent];
        
        if (key.compareTo((T) e) >= 0)  // 已满足堆性质
            break;
        
        es[k] = e;      // 父节点下移
        k = parent;     // 继续向上比较
    }
    es[k] = key;        // 插入到正确位置
}

/**
 * 使用比较器进行上浮操作
 */
private static <T> void siftUpUsingComparator(
        int k, T x, Object[] es, Comparator<? super T> cmp) {
    while (k > 0) {
        int parent = (k - 1) >>> 1;
        Object e = es[parent];
        
        if (cmp.compare(x, (T) e) >= 0)
            break;
        
        es[k] = e;
        k = parent;
    }
    es[k] = x;
}
6.3.2 出队操作 - take方法
/**
 * 阻塞式获取并移除队头元素(优先级最高的元素)
 */
public E take() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lockInterruptibly();
    E result;
    try {
        // 队列空时等待
        while ((result = dequeue()) == null)
            notEmpty.await();
    } finally {
        lock.unlock();
    }
    return result;
}

/**
 * 非阻塞获取并移除队头元素
 */
public E poll() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        return dequeue();
    } finally {
        lock.unlock();
    }
}

/**
 * 出队操作 - 移除堆顶元素并重新堆化
 * 调用前必须持有锁
 */
private E dequeue() {
    final Object[] es;
    final E result;
    
    if ((result = (E) ((es = queue)[0])) != null) {
        final int n;
        final E x = (E) es[(n = --size)];  // 获取最后一个元素
        es[n] = null;                      // 清空最后位置
        
        if (n > 0) {
            final Comparator<? super E> cmp;
            if ((cmp = comparator) == null)
                siftDownComparable(0, x, es, n);     // 自然排序下沉
            else
                siftDownUsingComparator(0, x, es, n, cmp);  // 比较器下沉
        }
    }
    return result;
}

/**
 * 使用自然排序进行下沉操作
 * 维护最小堆性质
 */
private static <T> void siftDownComparable(int k, T x, Object[] es, int n) {
    Comparable<? super T> key = (Comparable<? super T>) x;
    int half = n >>> 1;  // 非叶子节点的边界
    
    while (k < half) {
        int child = (k << 1) + 1;    // 左子节点
        Object c = es[child];
        int right = child + 1;       // 右子节点
        
        // 选择较小的子节点
        if (right < n && ((Comparable<? super T>) c).compareTo((T) es[right]) > 0)
            c = es[child = right];
        
        if (key.compareTo((T) c) <= 0)  // 已满足堆性质
            break;
        
        es[k] = c;      // 子节点上移
        k = child;      // 继续向下比较
    }
    es[k] = key;        // 插入到正确位置
}

6.4 动态扩容机制

/**
 * 尝试扩容数组
 * 使用自旋锁避免多线程同时扩容
 */
private void tryGrow(Object[] array, int oldCap) {
    lock.unlock(); // 释放主锁,允许其他操作继续
    Object[] newArray = null;
    
    // 使用CAS获取扩容锁
    if (allocationSpinLock == 0 &&
        ALLOCATIONSPINLOCK.compareAndSet(this, 0, 1)) {
        try {
            int newCap = oldCap + ((oldCap < 64) ?
                                   (oldCap + 2) :     // 小容量时快速增长
                                   (oldCap >> 1));    // 大容量时增长50%
            
            if (newCap - MAX_ARRAY_SIZE > 0) {    // 检查溢出
                int minCap = oldCap + 1;
                if (minCap < 0 || minCap > MAX_ARRAY_SIZE)
                    throw new OutOfMemoryError();
                newCap = MAX_ARRAY_SIZE;
            }
            
            if (newCap > oldCap && queue == array)
                newArray = new Object[newCap];
        } finally {
            allocationSpinLock = 0;  // 释放扩容锁
        }
    }
    
    // 如果当前线程没有获得扩容锁,让出CPU
    if (newArray == null)
        Thread.yield();
    
    lock.lock();  // 重新获取主锁
    
    // 如果扩容成功,复制数据
    if (newArray != null && queue == array) {
         queue = newArray;
         System.arraycopy(array, 0, newArray, 0, oldCap);
     }
 }

6.5 堆结构可视化

graph TD
    subgraph "PriorityBlockingQueue 堆结构"
        A["索引0: 1 (堆顶-最小值)"] --> B["索引1: 3"]
        A --> C["索引2: 2"]
        B --> D["索引3: 7"]
        B --> E["索引4: 5"]
        C --> F["索引5: 4"]
        C --> G["索引6: 6"]
        D --> H["索引7: 9"]
        D --> I["索引8: 8"]
    end
    
    subgraph "堆操作流程"
        J["插入元素"] --> K["添加到数组末尾"]
        K --> L["向上调整(siftUp)"]
        L --> M["维护堆性质"]
        
        N["删除元素"] --> O["移除堆顶"]
        O --> P["末尾元素移到堆顶"]
        P --> Q["向下调整(siftDown)"]
        Q --> R["维护堆性质"]
    end

6.6 PriorityBlockingQueue特性总结

  • 无界容量:理论上无容量限制,动态扩容
  • 优先级排序:基于二叉堆实现,支持自然排序和自定义比较器
  • 单锁设计:使用一个ReentrantLock保护所有操作
  • 扩容优化:使用自旋锁避免多线程同时扩容
  • 不支持null:不允许插入null元素
  • 非FIFO:按优先级出队,不是先进先出

7. SynchronousQueue 源码解析

7.1 核心设计理念

从项目源码 SynchronousQueue.java 中可以看到其独特的设计:

/**
 * 同步队列 - 没有内部容量的阻塞队列
 * 每个插入操作必须等待另一个线程的移除操作,反之亦然
 * 特点:零容量、直接传递、支持公平和非公平模式
 */
public class SynchronousQueue<E> extends AbstractQueue<E>
        implements BlockingQueue<E>, java.io.Serializable {
    
    // ========== 核心字段 ==========
    
    /** 
     * 传输器 - 实际执行put/take操作的核心组件
     * 根据公平性选择不同的实现:
     * - 公平模式:TransferQueue (FIFO)
     * - 非公平模式:TransferStack (LIFO)
     */
    private transient volatile Transferer<E> transferer;
    
    /** 
     * CPU数量,用于自旋优化
     */
    static final int NCPUS = Runtime.getRuntime().availableProcessors();
    
    /** 
     * 在阻塞前的自旋次数
     * 多核系统下进行自旋优化
     */
    static final int maxTimedSpins = (NCPUS < 2) ? 0 : 32;
    
    /** 
     * 无超时操作的自旋次数
     */
    static final int maxUntimedSpins = maxTimedSpins * 16;
    
    /** 
     * 自旋时间阈值(纳秒)
     * 超过此时间才进行自旋
     */
    static final long spinForTimeoutThreshold = 1000L;
}

7.2 构造方法分析

/**
 * 创建非公平模式的SynchronousQueue
 * 默认使用LIFO顺序(栈结构)
 */
public SynchronousQueue() {
    this(false);
}

/**
 * 创建指定公平性的SynchronousQueue
 * @param fair true表示公平模式(FIFO),false表示非公平模式(LIFO)
 */
public SynchronousQueue(boolean fair) {
    transferer = fair ? new TransferQueue<E>() : new TransferStack<E>();
}

7.3 核心抽象类 - Transferer

/**
 * 传输器抽象类
 * 定义了put/take操作的统一接口
 */
abstract static class Transferer<E> {
    /**
     * 执行put或take操作
     * @param e 如果非null,表示put操作;如果null,表示take操作
     * @param timed 是否有超时限制
     * @param nanos 超时时间(纳秒)
     * @return put操作返回传递的元素,take操作返回接收的元素
     *         如果被中断或超时,返回null
     */
    abstract E transfer(E e, boolean timed, long nanos);
}

7.4 非公平模式 - TransferStack

/**
 * 非公平传输器 - 基于栈的LIFO实现
 * 后进先出,性能更好但可能导致饥饿
 */
static final class TransferStack<E> extends Transferer<E> {
    
    // ========== 节点类型常量 ==========
    
    /** 请求数据的节点(take操作) */
    static final int REQUEST    = 0;
    /** 提供数据的节点(put操作) */
    static final int DATA       = 1;
    /** 正在匹配的节点 */
    static final int FULFILLING = 2;
    
    /** 检查节点是否为匹配模式 */
    static boolean isFulfilling(int m) { return (m & FULFILLING) != 0; }
    
    /** 
     * 栈节点定义
     */
    static final class SNode {
        volatile SNode next;        // 下一个节点
        volatile SNode match;       // 匹配的节点
        volatile Thread waiter;     // 等待的线程
        Object item;                // 数据项
        int mode;                   // 节点模式
        
        SNode(Object item) {
            this.item = item;
        }
        
        /**
         * 尝试CAS设置next指针
         */
        boolean casNext(SNode cmp, SNode val) {
            return cmp == next && SNEXT.compareAndSet(this, cmp, val);
        }
        
        /**
         * 尝试匹配当前节点
         * @param s 要匹配的节点
         * @return 匹配成功返回true
         */
        boolean tryMatch(SNode s) {
            if (match == null &&
                SMATCH.compareAndSet(this, null, s)) {
                Thread w = waiter;
                if (w != null) {    // 唤醒等待线程
                    waiter = null;
                    LockSupport.unpark(w);
                }
                return true;
            }
            return match == s;
        }
        
        /**
         * 取消节点(中断或超时时调用)
         */
        void tryCancel() {
            SMATCH.compareAndSet(this, null, this);
        }
        
        /**
         * 检查节点是否已取消
         */
        boolean isCancelled() {
            return match == this;
        }
    }
    
    /** 栈顶指针 */
    volatile SNode head;
    
    /**
     * CAS设置栈顶
     */
    boolean casHead(SNode h, SNode nh) {
        return h == head && SHEAD.compareAndSet(this, h, nh);
    }

7.5 TransferStack的transfer方法

    /**
     * TransferStack的核心传输方法
     */
    @SuppressWarnings("unchecked")
    E transfer(E e, boolean timed, long nanos) {
        SNode s = null; // 当前节点
        int mode = (e == null) ? REQUEST : DATA;
        
        for (;;) {
            SNode h = head;
            
            // 情况1:栈为空或栈顶节点模式相同
            if (h == null || h.mode == mode) {
                // 超时检查
                if (timed && nanos <= 0L) {
                    if (h != null && h.isCancelled())
                        casHead(h, h.next);     // 清理取消的节点
                    else
                        return null;            // 超时返回
                } 
                // 创建新节点并压入栈
                else if (casHead(h, s = snode(s, e, h, mode))) {
                    SNode m = awaitFulfill(s, timed, nanos);
                    if (m == s) {               // 被取消
                        clean(s);
                        return null;
                    }
                    // 清理栈顶的匹配节点对
                    if ((h = head) != null && h.next == s)
                        casHead(h, s.next);
                    return (E) ((mode == REQUEST) ? m.item : s.item);
                }
            }
            // 情况2:栈顶是FULFILLING模式(正在匹配)
            else if (!isFulfilling(h.mode)) {
                // 检查是否已取消
                if (h.isCancelled())
                    casHead(h, h.next);
                // 尝试匹配栈顶节点
                else if (casHead(h, s=snode(s, e, h, FULFILLING|mode))) {
                    for (;;) {
                        SNode m = s.next;
                        if (m == null) {        // 匹配的节点消失了
                            casHead(s, null);
                            s = null;
                            break;
                        }
                        SNode mn = m.next;
                        // 尝试匹配
                        if (m.tryMatch(s)) {
                            casHead(s, mn);
                            return (E) ((mode == REQUEST) ? m.item : s.item);
                        } else {
                            s.casNext(m, mn);   // 匹配失败,移除m
                        }
                    }
                }
            }
            // 情况3:帮助其他线程完成匹配
            else {
                SNode m = h.next;
                if (m == null)
                    casHead(h, null);
                else {
                    SNode mn = m.next;
                    if (m.tryMatch(h))
                        casHead(h, mn);
                    else
                        h.casNext(m, mn);
                }
            }
        }
    }
    
    /**
     * 等待匹配完成
     */
    SNode awaitFulfill(SNode s, boolean timed, long nanos) {
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        Thread w = Thread.currentThread();
        int spins = shouldSpin(s) ? 
                   (timed ? maxTimedSpins : maxUntimedSpins) : 0;
        
        for (;;) {
            // 检查中断
            if (w.isInterrupted())
                s.tryCancel();
            
            SNode m = s.match;
            if (m != null)
                return m;
            
            // 超时检查
            if (timed) {
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L) {
                    s.tryCancel();
                    continue;
                }
            }
            
            // 自旋等待
            if (spins > 0) {
                spins = shouldSpin(s) ? (spins - 1) : 0;
            }
            // 设置等待线程
            else if (s.waiter == null) {
                s.waiter = w;
            }
            // 阻塞等待
            else if (!timed) {
                LockSupport.park(this);
            }
            else if (nanos > spinForTimeoutThreshold) {
                 LockSupport.parkNanos(this, nanos);
             }
         }
     }

7.6 公平模式 - TransferQueue

/**
 * 公平传输器 - 基于队列的FIFO实现
 * 先进先出,保证公平性但性能略低
 */
static final class TransferQueue<E> extends Transferer<E> {
    
    /**
     * 队列节点定义
     */
    static final class QNode {
        volatile QNode next;          // 下一个节点
        volatile Object item;         // 数据项
        volatile Thread waiter;       // 等待的线程
        final boolean isData;         // 是否为数据节点
        
        QNode(Object item, boolean isData) {
            this.item = item;
            this.isData = isData;
        }
        
        /**
         * CAS设置next指针
         */
        boolean casNext(QNode cmp, QNode val) {
            return next == cmp && QNEXT.compareAndSet(this, cmp, val);
        }
        
        /**
         * CAS设置item
         */
        boolean casItem(Object cmp, Object val) {
            return item == cmp && QITEM.compareAndSet(this, cmp, val);
        }
        
        /**
         * 取消节点
         */
        void tryCancel(Object cmp) {
            QITEM.compareAndSet(this, cmp, this);
        }
        
        /**
         * 检查是否已取消
         */
        boolean isCancelled() {
            return item == this;
        }
        
        /**
         * 检查是否为已知的数据节点
         */
        boolean isOffList() {
            return next == this;
        }
    }
    
    /** 队列头指针 */
    transient volatile QNode head;
    /** 队列尾指针 */
    transient volatile QNode tail;
    
    /**
     * 清理队列中的取消节点
     */
    transient volatile QNode cleanMe;
    
    TransferQueue() {
        QNode h = new QNode(null, false); // 虚拟头节点
        head = h;
        tail = h;
    }
    
    /**
     * TransferQueue的核心传输方法
     */
    @SuppressWarnings("unchecked")
    E transfer(E e, boolean timed, long nanos) {
        QNode s = null;
        boolean isData = (e != null);
        
        for (;;) {
            QNode t = tail;
            QNode h = head;
            
            if (t == null || h == null)         // 未初始化
                continue;
            
            // 队列为空或尾节点模式相同
            if (h == t || t.isData == isData) {
                QNode tn = t.next;
                if (t != tail)                  // 尾指针不一致,重试
                    continue;
                if (tn != null) {               // 尾指针落后,推进
                    advanceTail(t, tn);
                    continue;
                }
                if (timed && nanos <= 0L)       // 超时检查
                    return null;
                if (s == null)
                    s = new QNode(e, isData);
                if (!t.casNext(null, s))        // 链接失败,重试
                    continue;
                
                advanceTail(t, s);              // 推进尾指针
                Object x = awaitFulfill(s, e, timed, nanos);
                if (x == s) {                   // 等待被取消
                    clean(t, s);
                    return null;
                }
                
                if (!s.isOffList()) {           // 节点未出队
                    advanceHead(t, s);
                    if (x != null)
                        s.item = s;
                    s.waiter = null;
                }
                return (x != null) ? (E)x : e;
            }
            // 队列中有互补节点,尝试匹配
            else {
                QNode m = h.next;               // 头节点的下一个
                if (t != tail || m == null || h != head)
                    continue;                   // 不一致,重试
                
                Object x = m.item;
                if (isData == (x != null) ||    // 模式不匹配
                    x == m ||                   // 已取消
                    !m.casItem(x, e)) {         // CAS失败
                    advanceHead(h, m);          // 推进头指针
                    continue;
                }
                
                advanceHead(h, m);              // 匹配成功,推进头指针
                LockSupport.unpark(m.waiter);  // 唤醒等待线程
                return (x != null) ? (E)x : e;
            }
        }
    }
    
    /**
     * 等待匹配完成
     */
    Object awaitFulfill(QNode s, Object e, boolean timed, long nanos) {
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        Thread w = Thread.currentThread();
        int spins = (head.next == s) ?
                   (timed ? maxTimedSpins : maxUntimedSpins) : 0;
        
        for (;;) {
            if (w.isInterrupted())
                s.tryCancel(e);
            
            Object x = s.item;
            if (x != e)
                return x;
            
            if (timed) {
                nanos = deadline - System.nanoTime();
                if (nanos <= 0L) {
                    s.tryCancel(e);
                    continue;
                }
            }
            
            if (spins > 0) {
                --spins;
            }
            else if (s.waiter == null) {
                s.waiter = w;
            }
            else if (!timed) {
                LockSupport.park(this);
            }
            else if (nanos > spinForTimeoutThreshold) {
                LockSupport.parkNanos(this, nanos);
            }
        }
    }
}

7.7 核心操作方法

/**
 * 插入元素 - 必须等待消费者线程
 */
public void put(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    if (transferer.transfer(e, false, 0) == null) {
        Thread.interrupted();
        throw new InterruptedException();
    }
}

/**
 * 非阻塞插入 - 如果没有等待的消费者立即返回false
 */
public boolean offer(E e) {
    if (e == null) throw new NullPointerException();
    return transferer.transfer(e, true, 0) != null;
}

/**
 * 超时插入
 */
public boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException {
    if (e == null) throw new NullPointerException();
    if (transferer.transfer(e, true, unit.toNanos(timeout)) != null)
        return true;
    if (!Thread.interrupted())
        return false;
    throw new InterruptedException();
}

/**
 * 获取元素 - 必须等待生产者线程
 */
public E take() throws InterruptedException {
    E e = transferer.transfer(null, false, 0);
    if (e != null)
        return e;
    Thread.interrupted();
    throw new InterruptedException();
}

/**
 * 非阻塞获取 - 如果没有等待的生产者立即返回null
 */
public E poll() {
    return transferer.transfer(null, true, 0);
}

/**
 * 超时获取
 */
public E poll(long timeout, TimeUnit unit) throws InterruptedException {
    E e = transferer.transfer(null, true, unit.toNanos(timeout));
    if (e != null || !Thread.interrupted())
        return e;
    throw new InterruptedException();
}

/**
 * 队列大小始终为0
 */
public int size() {
    return 0;
}

/**
 * 队列始终为空
 */
public boolean isEmpty() {
    return true;
}

7.8 SynchronousQueue工作流程图

sequenceDiagram
    participant P as Producer
    participant SQ as SynchronousQueue
    participant C as Consumer
    
    Note over P,C: 场景1:生产者先到达
    P->>SQ: put(item)
    Note over SQ: 创建DATA节点,等待匹配
    C->>SQ: take()
    Note over SQ: 匹配成功,直接传递
    SQ->>C: 返回item
    SQ->>P: put操作完成
    
    Note over P,C: 场景2:消费者先到达
    C->>SQ: take()
    Note over SQ: 创建REQUEST节点,等待匹配
    P->>SQ: put(item)
    Note over SQ: 匹配成功,直接传递
    SQ->>C: 返回item
    SQ->>P: put操作完成
    
    Note over P,C: 场景3:非阻塞操作
    P->>SQ: offer(item)
    Note over SQ: 没有等待的消费者
    SQ->>P: 返回false

7.9 SynchronousQueue特性总结

  • 零容量:不存储任何元素,每个操作必须等待匹配
  • 直接传递:生产者直接将元素传递给消费者
  • 双模式:支持公平(FIFO)和非公平(LIFO)模式
  • 高性能:无锁算法,使用CAS操作
  • 自旋优化:多核环境下使用自旋减少上下文切换
  • 适用场景:线程池、生产者-消费者直接交换

8. LinkedBlockingDeque 源码解析

8.1 核心数据结构

从项目源码 LinkedBlockingDeque.java 中可以看到其双端队列的实现:

/**
 * 基于链表的双端阻塞队列
 * 支持从队头和队尾进行插入和删除操作
 * 特点:可选有界、双端操作、单锁设计
 */
public class LinkedBlockingDeque<E>
        extends AbstractQueue<E>
        implements BlockingDeque<E>, java.io.Serializable {
    
    // ========== 核心字段 ==========
    
    /**
     * 双向链表节点
     */
    static final class Node<E> {
        /**
         * 节点存储的元素
         * 如果为null且节点未被移除,表示这是一个占位符节点
         */
        E item;
        
        /**
         * 前驱节点指针
         * 如果为null,表示这是第一个节点
         */
        Node<E> prev;
        
        /**
         * 后继节点指针
         * 如果为null,表示这是最后一个节点
         */
        Node<E> next;
        
        Node(E x) {
            item = x;
        }
    }
    
    /** 
     * 队列头节点指针
     * 不变性:first.prev == null
     */
    transient Node<E> first;
    
    /** 
     * 队列尾节点指针
     * 不变性:last.next == null
     */
    transient Node<E> last;
    
    /** 队列中元素的数量 */
    private transient int count;
    
    /** 队列的最大容量 */
    private final int capacity;
    
    /** 保护所有操作的锁 */
    final ReentrantLock lock = new ReentrantLock();
    
    /** 等待take操作的条件队列 */
    private final Condition notEmpty = lock.newCondition();
    
    /** 等待put操作的条件队列 */
     private final Condition notFull = lock.newCondition();
 }

8.2 构造方法分析

/**
 * 创建无界LinkedBlockingDeque
 */
public LinkedBlockingDeque() {
    this(Integer.MAX_VALUE);
}

/**
 * 创建指定容量的LinkedBlockingDeque
 */
public LinkedBlockingDeque(int capacity) {
    if (capacity <= 0) throw new IllegalArgumentException();
    this.capacity = capacity;
}

/**
 * 创建包含指定集合元素的LinkedBlockingDeque
 */
public LinkedBlockingDeque(Collection<? extends E> c) {
    this(Integer.MAX_VALUE);
    final ReentrantLock lock = this.lock;
    lock.lock(); // 确保可见性,虽然构造时不需要
    try {
        for (E e : c) {
            if (e == null)
                throw new NullPointerException();
            if (!linkLast(new Node<E>(e)))
                throw new IllegalStateException("Deque full");
        }
    } finally {
        lock.unlock();
    }
}

8.3 核心操作方法

8.3.1 队头插入操作
/**
 * 在队头插入元素 - 阻塞版本
 */
public void putFirst(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    Node<E> node = new Node<E>(e);
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        while (!linkFirst(node))  // 队列满时等待
            notFull.await();
    } finally {
        lock.unlock();
    }
}

/**
 * 在队头插入元素 - 非阻塞版本
 */
public boolean offerFirst(E e) {
    if (e == null) throw new NullPointerException();
    Node<E> node = new Node<E>(e);
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        return linkFirst(node);
    } finally {
        lock.unlock();
    }
}

/**
 * 链接节点到队头
 * 调用前必须持有锁
 */
private boolean linkFirst(Node<E> node) {
    if (count >= capacity)  // 队列已满
        return false;
    Node<E> f = first;
    node.next = f;
    first = node;
    if (last == null)       // 队列原本为空
        last = node;
    else
        f.prev = node;
    ++count;
    notEmpty.signal();      // 唤醒等待的消费者
    return true;
}
8.3.2 队尾插入操作
/**
 * 在队尾插入元素 - 阻塞版本
 */
public void putLast(E e) throws InterruptedException {
    if (e == null) throw new NullPointerException();
    Node<E> node = new Node<E>(e);
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        while (!linkLast(node))   // 队列满时等待
            notFull.await();
    } finally {
        lock.unlock();
    }
}

/**
 * 在队尾插入元素 - 非阻塞版本
 */
public boolean offerLast(E e) {
    if (e == null) throw new NullPointerException();
    Node<E> node = new Node<E>(e);
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        return linkLast(node);
    } finally {
        lock.unlock();
    }
}

/**
 * 链接节点到队尾
 * 调用前必须持有锁
 */
private boolean linkLast(Node<E> node) {
    if (count >= capacity)  // 队列已满
        return false;
    Node<E> l = last;
    node.prev = l;
    last = node;
    if (first == null)      // 队列原本为空
        first = node;
    else
        l.next = node;
    ++count;
    notEmpty.signal();      // 唤醒等待的消费者
    return true;
}
8.3.3 队头删除操作
/**
 * 从队头获取元素 - 阻塞版本
 */
public E takeFirst() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        E x;
        while ((x = unlinkFirst()) == null)  // 队列空时等待
            notEmpty.await();
        return x;
    } finally {
        lock.unlock();
    }
}

/**
 * 从队头获取元素 - 非阻塞版本
 */
public E pollFirst() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        return unlinkFirst();
    } finally {
        lock.unlock();
    }
}

/**
 * 移除队头节点
 * 调用前必须持有锁
 */
private E unlinkFirst() {
    Node<E> f = first;
    if (f == null)          // 队列为空
        return null;
    Node<E> n = f.next;
    E item = f.item;
    f.item = null;
    f.next = f;             // 帮助GC
    first = n;
    if (n == null)          // 队列变为空
        last = null;
    else
        n.prev = null;
    --count;
    notFull.signal();       // 唤醒等待的生产者
    return item;
}
8.3.4 队尾删除操作
/**
 * 从队尾获取元素 - 阻塞版本
 */
public E takeLast() throws InterruptedException {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        E x;
        while ((x = unlinkLast()) == null)   // 队列空时等待
            notEmpty.await();
        return x;
    } finally {
        lock.unlock();
    }
}

/**
 * 从队尾获取元素 - 非阻塞版本
 */
public E pollLast() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        return unlinkLast();
    } finally {
        lock.unlock();
    }
}

/**
 * 移除队尾节点
 * 调用前必须持有锁
 */
private E unlinkLast() {
    Node<E> l = last;
    if (l == null)          // 队列为空
        return null;
    Node<E> p = l.prev;
    E item = l.item;
    l.item = null;
    l.prev = l;             // 帮助GC
    last = p;
    if (p == null)          // 队列变为空
        first = null;
    else
        p.next = null;
    --count;
    notFull.signal();       // 唤醒等待的生产者
    return item;
}

8.4 LinkedBlockingDeque结构图

graph LR
    subgraph "LinkedBlockingDeque 双向链表结构"
        A["first"] --> B["Node1"]
        B --> C["Node2"]
        C --> D["Node3"]
        D --> E["last"]
        
        B -.-> A
        C -.-> B
        D -.-> C
        E -.-> D
    end
    
    subgraph "双端操作"
        F["putFirst/offerFirst"] --> A
        G["takeFirst/pollFirst"] --> A
        H["putLast/offerLast"] --> E
        I["takeLast/pollLast"] --> E
    end

8.5 LinkedBlockingDeque特性总结

  • 双端操作:支持从队头和队尾进行插入和删除
  • 可选有界:可以指定容量,默认无界
  • 单锁设计:使用一个ReentrantLock保护所有操作
  • 双向链表:基于双向链表实现,支持高效的双端操作
  • FIFO/LIFO:可以作为队列(FIFO)或栈(LIFO)使用
  • 线程安全:所有操作都是线程安全的

9. 阻塞队列对比分析

9.1 特性对比表

特性ArrayBlockingQueueLinkedBlockingQueuePriorityBlockingQueueSynchronousQueueLinkedBlockingDeque
数据结构环形数组单向链表二叉堆栈/队列双向链表
容量限制有界可选有界无界零容量可选有界
锁机制单锁双锁单锁+自旋锁无锁(CAS)单锁
排序方式FIFOFIFO优先级直接传递FIFO/LIFO
公平性可选可选
内存开销中等中等最低中等
吞吐量中等中等最高中等
适用场景固定容量缓冲生产者-消费者任务调度线程池双端操作

图例说明:

  • 🔵 ArrayBlockingQueue:固定容量,单锁设计
  • 🟢 LinkedBlockingQueue:可选容量,双锁设计
  • 🟡 PriorityBlockingQueue:优先级排序,无界容量
  • 🔴 SynchronousQueue:零容量,直接传递
  • 🟣 LinkedBlockingDeque:双端操作,单锁设计

10. 最佳实践与选择指南

10.1 选择决策树

flowchart TD
    A["需要阻塞队列"] --> B{"是否需要优先级排序?"}
    B -->|是| C["PriorityBlockingQueue"]
    B -->|否| D{"是否需要直接传递?"}
    D -->|是| E["SynchronousQueue"]
    D -->|否| F{"是否需要双端操作?"}
    F -->|是| G["LinkedBlockingDeque"]
    F -->|否| H{"容量是否固定?"}
    H -->|是| I{"是否需要公平性?"}
    I -->|是| J["ArrayBlockingQueue(fair)"]
    I -->|否| K["ArrayBlockingQueue"]
    H -->|否| L{"是否需要高并发?"}
    L -->|是| M["LinkedBlockingQueue"]
    L -->|否| N["ArrayBlockingQueue"]

10.2 使用建议

10.2.1 ArrayBlockingQueue
  • 适用场景:固定大小的缓冲区、内存敏感的应用
  • 优势:内存占用少、缓存友好
  • 注意事项:单锁可能成为瓶颈
10.2.2 LinkedBlockingQueue
  • 适用场景:生产者-消费者模式、高并发场景
  • 优势:双锁设计、高吞吐量
  • 注意事项:内存开销较大
10.2.3 PriorityBlockingQueue
  • 适用场景:任务调度、优先级处理
  • 优势:自动排序、无界容量
  • 注意事项:不保证同优先级元素的顺序
10.2.4 SynchronousQueue
  • 适用场景:线程池、直接交换
  • 优势:零延迟、高性能
  • 注意事项:必须有配对的操作
10.2.5 LinkedBlockingDeque
  • 适用场景:工作窃取、双端操作
  • 优势:灵活的操作方式
  • 注意事项:单锁限制并发性

10.3 性能调优建议

  1. 容量设置:根据实际需求设置合适的容量
  2. 公平性权衡:公平性会降低性能,按需选择
  3. 批量操作:使用drainTo等批量操作提高效率
  4. 监控指标:关注队列大小、等待时间等指标
  5. 异常处理:正确处理中断和超时异常

总结

本文深入分析了Java并发包中的五种主要阻塞队列实现,从源码层面解析了它们的设计原理、实现机制和性能特点。每种阻塞队列都有其独特的适用场景:

  • ArrayBlockingQueue:适合固定容量的缓冲场景
  • LinkedBlockingQueue:适合高并发的生产者-消费者模式
  • PriorityBlockingQueue:适合需要优先级排序的任务调度
  • SynchronousQueue:适合直接传递的高性能场景
  • LinkedBlockingDeque:适合需要双端操作的复杂场景

理解这些队列的内部实现有助于在实际开发中做出正确的选择,并能够针对性地进行性能优化。