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、返回移除的元素。

posted @ 2025-02-19 18:29  jock_javaEE  阅读(29)  评论(0)    收藏  举报