fair参数只影响多线程争抢入队/出队时的等待顺序:true启用AQS公平锁,最久等待线程优先;false用非公平锁,吞吐高但可能饥饿。

ArrayBlockingQueue 构造时 fair 参数到底影响什么
它只影响多个线程争抢同一个“出队/入队”操作时的等待顺序,不影响容量、线程安全或基本行为。设为 true 会启用基于 AQS 的公平锁,让等待最久的线程优先获得许可;设为 false(默认)则用非公平锁,可能产生线程饥饿但吞吐略高。
常见错误现象:开了 fair = true 后吞吐明显下降,误以为是队列本身变慢了——其实是锁调度开销增大,尤其在高并发短任务场景下更明显。
- 公平模式适合对响应时间敏感、且能接受吞吐折损的场景,比如实时告警通道
- 非公平模式更适合吞吐优先的后台任务队列,比如日志批量写入
-
fair不影响peek()、size()这类不阻塞的方法,它们始终无锁
offer()、put()、add() 三个入队方法的区别必须分清
它们看似都往队列里塞元素,但异常策略和阻塞行为完全不同,混用容易导致逻辑卡死或静默丢数据。
常见错误现象:用 add() 往满队列加元素,抛出 IllegalStateException 却没捕获,程序意外崩溃;或者该用 put() 等待空位时用了 offer(),结果返回 false 后没处理,任务直接消失。
立即学习“Java免费学习笔记(深入)”;
-
add(e):队列满时立即抛IllegalStateException,不推荐在线上使用 -
offer(e):成功返回true,满时返回false,适合“尽力而为”场景 -
put(e):满时阻塞,直到有空间,适合强可靠性要求(如订单入队)
poll()、take()、remove() 出队行为差异与空队列陷阱
空队列时的行为差异比入队更易踩坑,尤其 remove(Object) 是从头遍历查找并删除首个匹配项,不是取队首——这和 ArrayBlockingQueue 的设计初衷完全相悖。
常见错误现象:调用 remove("abc") 想删掉某个特定任务,结果遍历整个数组、触发锁、还可能删错位置;或者误用 poll() 在空队列返回 null 后没判空,后续 NPE。
-
poll():空时返回null,非阻塞 -
take():空时阻塞,直到有元素,适合消费者模型主循环 -
remove(Object o):遍历查找并移除第一个等于o的元素,O(n) 时间,慎用 -
remove()(无参):等价于poll(),但语义模糊,建议统一用poll()
容量固定 + 无法扩容,初始化后 size() 和 remainingCapacity() 就是铁律
它底层是 final 的 Object[],构造完容量就锁死。别指望靠 size() 动态判断能否扩容——它永远 ≤ 构造时传的 capacity,且 remainingCapacity() = capacity - size(),二者之和恒定。
常见错误现象:监控发现 size() 长期接近 capacity,想“动态调大”,结果只能重启服务;或者把 remainingCapacity() 当作“还能塞多少个不同对象”,忽略了泛型擦除和引用复用带来的实际内存压力。
- 容量选型必须结合峰值流量+单条消息大小+GC 压力预估,不能只看理论数字
-
size()是当前元素个数,不是内存占用,大对象堆内驻留时间可能远超队列生命周期 - 没有
clear()的替代方案,drainTo(Collection)是唯一高效清空手段
真正难的不是记住这几个方法,而是每次调用前下意识问一句:我此刻要的是“尽力塞”“必须塞”还是“宁可等”,以及“这个 remove 是真想删队首,还是手滑写了参数”。


















