REJAVA / LEARNING NOTES
第7课速查:BlockingQueue(阻塞队列)
随时回查术语、规则和示例;完整解释见对应课程。
根据课程材料整理
本次更新说明
- 页尾去掉本地资料入口。
- 整理为公开学习笔记,保留技术内容与练习。
1 · 是什么
线程安全队列,多了等待:队满时放入方等空位,队空时取出方等元素。主要用于生产者-消费者。
放入之前的操作 happens-before(先行发生关系) 取出之后的操作。
2 · 四组方法
| 抛异常 | 特殊值 | 一直等 | 等一会 | |
|---|---|---|---|---|
| 放 | add(追加方法) | offer(尝试放入方法)→false | put(写入方法) | offer(e,t,u) |
| 取 | remove | poll(尝试取出方法)→null(空值) | take(阻塞取出方法) | poll(t,u) |
| 看 | element | peek | — | — |
请求线程用 offer(尝试放入方法);后台消费用 take(阻塞取出方法)。不收 null(空值)。等待被中断抛 InterruptedException(中断异常),标记已清除,catch 里 Thread.currentThread().interrupt()。
3 · 常用实现
ArrayBlockingQueue(数组阻塞队列): 数组,必须指定容量,一把锁。
LinkedBlockingQueue(链式阻塞队列): 链表,容量可选,不传=Integer.MAX_VALUE(整数类型最大值),两把锁;官方:吞吐通常更高、性能更难预测。 一定传容量。
SynchronousQueue(同步移交队列): 容量 0,一手交一手(newCachedThreadPool)。
PriorityBlockingQueue(优先级阻塞队列) 按优先级、 DelayQueue(延迟队列) 到期才取,均无界。
4 · 内部怎么等
ReentrantLock(可重入锁)+Condition(条件等待室)。await 放开锁去睡,signal 叫醒,醒来要重新拿锁。
数组版: 一把锁+notFull/notEmpty;while (count == items.length) notFull.await();。while 防虚假唤醒。
链表版: putLock 管尾、takeLock 管头,元素个数用 AtomicInteger(原子整数类);从空变非空才叫醒取出方(连锁唤醒)。
5 · 有界与线程池
newFixedThreadPool=无容量 LinkedBlockingQueue(链式阻塞队列) → 任务堆积耗尽内存,最大线程数失效。newCachedThreadPool=SynchronousQueue(同步移交队列)+最大线程数无上限。
生产用 ThreadPoolExecutor(线程池执行器)+有界队列;队满 offer(尝试放入方法) 失败或超时,把压力传回上游(背压)。容量 ≈ 每秒处理量 × 可接受等待秒数,再压测。
6 · 手写生产者-消费者
有界队列;生产者 put(写入方法)、消费者 take(阻塞取出方法),不自己 sleep 轮询;生产者最后放结束标记,消费者取到就 break(跳出循环语句); 几个消费者就放几个标记 ;catch 中断后恢复标记。
局限:队列在进程内存里,重启会丢、多实例不共享 → 需要时用消息队列。