一、LinkedBlockingQueue的poll方法底层原理
LinkedBlockingQueue 的 poll 方法用于从队列头部移除并返回元素。如果队列为空,poll 方法会立即返回 null,而不会阻塞线程
1、poll 方法的作用
-
从队列头部移除并返回元素。
-
如果队列为空,立即返回 null。
-
该方法是非阻塞的,适用于需要快速响应的场景。
2、poll 方法的源码
以下是 LinkedBlockingQueue 中 poll 方法的源码(基于 JDK 17):
3、源码解析
(1)检查队列是否为空
-
count 是一个 AtomicInteger,表示当前队列中的元素数量。
-
如果队列为空(count.get() == 0),立即返回 null。
(2)获取锁
-
takeLock 是 LinkedBlockingQueue 的成员变量,用于控制移除操作的并发访问。
-
调用 lock() 方法获取锁。
(3)再次检查队列是否为空
- 在加锁后再次检查队列是否为空,避免在加锁期间队列状态发生变化
(4)移除元素
-
调用 dequeue 方法从队列头部移除节点并返回其元素。
-
dequeue 方法的实现:
(5)更新元素数量
- 使用 AtomicInteger 的 getAndDecrement 方法将队列元素数量减 1,并返回减 1 之前的值(c)
(6)唤醒其他消费者线程
- 如果移除后队列不为空(c > 1),调用 notEmpty.signal() 唤醒其他可能正在等待的消费者线程。
(7)释放锁
- 在 finally 块中释放锁,确保锁一定会被释放,避免死锁。
(8)唤醒生产者线程
-
如果移除前队列已满(c == capacity),调用 signalNotFull() 唤醒可能正在等待的生产者线程。
-
signalNotFull() 的实现:
(9)返回移除的元素
- 返回从队列头部移除的元素。
二、关键点总结
-
非阻塞:如果队列为空,poll 方法会立即返回 null,而不会阻塞线程。
-
锁分离:LinkedBlockingQueue 使用两把锁(putLock 和 takeLock),分别控制插入和移除操作,提高了并发性能。
-
条件变量:使用 notFull 和 notEmpty 两个 Condition 实现线程的阻塞和唤醒。
-
线程安全:通过锁和原子变量(AtomicInteger)保证线程安全。
三、与 take 方法的对比
四、示例代码
以下是一个简单的示例,展示 poll 方法的使用场景: