LinkedBlockingQueue的take方法底层源码
一、LinkedBlockingQueue的take方法底层源码
LinkedBlockingQueue 的 take 方法是其核心方法之一,用于从队列头部移除并返回元素。如果队列为空,调用 take 方法的线程会被阻塞,直到队列中有新元素
1、take 方法的作用
-
从队列头部移除并返回元素。
-
如果队列为空,当前线程会被阻塞,直到队列中有新元素。
-
该方法会返回移除的元素,如果线程被中断,会抛出 InterruptedException。
2、take 方法的源码
以下是 LinkedBlockingQueue 中 take 方法的源码(基于 JDK 17):

3、源码解析
(1)获取锁

-
takeLock 是 LinkedBlockingQueue 的成员变量,用于控制移除操作的并发访问
-
lockInterruptibly() 方法会尝试获取锁,如果线程被中断,会抛出 InterruptedException
(2)检查队列是否为空

-
count 是一个 AtomicInteger,表示当前队列中的元素数量。
-
如果队列为空(count.get() == 0),当前线程会调用 notEmpty.await() 进入等待状态,直到队列中有新元素。
-
notEmpty 是一个 Condition 对象,用于实现消费者线程的阻塞和唤醒。
(3)移除元素

- dequeue 方法从队列头部移除节点并返回其元素:

a、head 是队列的虚拟头节点(不存储实际数据),head.next 是实际的第一个节点。
b、将 head 指向下一个节点,并返回原第一个节点的元素。
c、将原第一个节点的 item 置为 null,帮助垃圾回收。
(4)更新元素数量

- 使用 AtomicInteger 的 getAndDecrement 方法将队列元素数量减 1,并返回减 1 之前的值(c)
(5)唤醒其他消费者线程

- 如果移除后队列不为空(c > 1),调用 notEmpty.signal() 唤醒其他可能正在等待的消费者线程。
(6)释放锁

- 在 finally 块中释放锁,确保锁一定会被释放,避免死锁。
(7)唤醒生产者线程

-
如果移除前队列已满(c == capacity),调用 signalNotFull() 唤醒可能正在等待的生产者线程。
-
signalNotFull() 的实现:

获取 putLock,然后调用 notFull.signal() 唤醒生产者线程
(8)返回移除的元素

- 返回从队列头部移除的元素。
二、示例流程图
以下是 take 方法的执行流程图:
1、获取 takeLock。
2、检查队列是否为空:
- 如果为空,等待 notEmpty 条件。
3、从队列头部移除节点。
4、更新元素数量。
5、如果队列不为空,唤醒其他消费者线程。
6、释放 takeLock。
7、如果移除前队列已满,唤醒生产者线程。
8、返回移除的元素。

浙公网安备 33010602011771号