Java中Queue接口不提供默认FIFO阻塞行为,具体FIFO特性取决于实现类:ArrayDeque(推荐)、ConcurrentLinkedQueue或LinkedBlockingQueue等,需按线程安全与阻塞需求选择。

Java里Queue接口默认不提供FIFO的阻塞行为
Java的Queue接口本身只是定义了入队(add/offer)、出队(remove/poll)、查看头元素(element/peek)等契约,并不保证线程安全,也不强制FIFO——它只是“建议”实现为FIFO。实际是否FIFO,取决于你选的具体实现类。
常见误区是直接用new Queue(),这根本不能编译,因为Queue是接口。必须选一个实现类:
-
LinkedList:非线程安全,FIFO,适合单线程或已加锁场景 -
ArrayDeque:非线程安全,FIFO,性能优于LinkedList(推荐作为默认选择) -
ConcurrentLinkedQueue:线程安全,无界,FIFO,但size()不是O(1) -
LinkedBlockingQueue:线程安全,可选有界/无界,FIFO,支持阻塞操作(如take())
ArrayDeque比LinkedList更适合做普通FIFO队列
ArrayDeque底层用循环数组,offer()和poll()平均时间复杂度都是O(1),内存局部性好;而LinkedList是双向链表,每次操作要分配/释放节点对象,GC压力大,且缓存不友好。
除非你需要在队列中间插入或删除(这不是Queue接口的用途),否则别选LinkedList当队列用。它被设计成List和Deque双实现,但作为队列纯属“能用,不优”。
立即学习“Java免费学习笔记(深入)”;
Queuequeue = new ArrayDeque<>(); queue.offer("first"); queue.offer("second"); System.out.println(queue.poll()); // 输出 "first" System.out.println(queue.poll()); // 输出 "second"
别在多线程环境里直接用ArrayDeque或LinkedList
这两个类都不保证线程安全。多个线程同时调用offer()和poll()可能引发数据错乱、丢失元素,甚至ConcurrentModificationException(尤其遍历时)。
如果需要线程安全的FIFO队列,按场景选:
- 高吞吐、不关心阻塞 → 用
ConcurrentLinkedQueue - 需要阻塞等待(比如生产者-消费者模型)→ 用
LinkedBlockingQueue,并明确指定容量避免无限增长 - 需要公平锁或更多控制 → 考虑
PriorityBlockingQueue(注意:它不是FIFO!)或自己包装加锁
错误示范:static Queue —— 多线程下必出问题。
offer()和add()的区别常被忽略
两者都用于入队,但异常策略不同:
-
add():失败时抛IllegalStateException(比如有界队列满时) -
offer():失败时返回false,更利于程序判断和恢复
同理,remove() vs poll()(空队列时前者抛NoSuchElementException,后者返回null),element() vs peek()(前者抛异常,后者返回null)。
日常编码中,优先用offer()/poll()/peek(),它们更健壮,也符合“队列可能满或空”的现实假设。
FIFO只是Queue的一种语义约定,Java不会替你校验实现是否真按顺序进出;选错实现类、忽略线程安全、混淆add和offer的异常行为,这三个点最容易在真实项目里埋雷。










