LinkedList适合作为栈或队列:栈用push/pop/peek,队列用offer/poll/peek;避免ArrayList因O(n)删除和语义弱;注意非线程安全,高并发应选ArrayDeque或ConcurrentLinkedQueue。

用 LinkedList 当队列:add() 和 poll() 是关键
Java 的 LinkedList 实现了 Queue 接口,天然支持 FIFO 行为。但别直接用 add() 和 remove()——它们在失败时抛异常,而队列操作更常需要“失败静默”语义。
推荐组合:
-
offer(E):入队,成功返回true,容量满(对有界队列)或内部异常时返回false -
poll():出队,队空时返回null,不抛异常 -
peek():只看队首,不移除,队空也返回null
示例:
LinkedListqueue = new LinkedList<>(); queue.offer("a"); queue.offer("b"); String head = queue.poll(); // 返回 "a" String next = queue.peek(); // 返回 "b"
用 LinkedList 当栈:push() 和 pop() 更直观
LinkedList 同时实现了 Deque 接口,提供了标准栈操作方法。注意:不要混用 addFirst()/removeFirst() 和 push()/pop()——虽然效果相同,但语义混乱且易引发维护困惑。
立即学习“Java免费学习笔记(深入)”;
必须用的三个方法:
-
push(E):压栈,等价于addFirst(e) -
pop():出栈,等价于removeFirst(),栈空时抛NoSuchElementException -
peek():查看栈顶,等价于getFirst(),栈空时也抛异常
如果需避免异常,改用 isEmpty() 预检:
LinkedListstack = new LinkedList<>(); stack.push(1); stack.push(2); if (!stack.isEmpty()) { int top = stack.pop(); // 返回 2 }
为什么不用 ArrayList 模拟栈/队列?
ArrayList 在尾部增删是 O(1),但模拟队列时的 remove(0) 是 O(n),因为要整体移动元素;模拟栈虽可用 add(size, e) 和 remove(size-1),但缺乏语义表达力,且无内置空检查保障。
LinkedList 的优势在于:
- 头部/尾部插入删除均为 O(1),双向链表结构决定
- 所有栈/队列接口方法都有对应实现,无需手动索引计算
- 不涉及扩容机制,无
ArrayList的grow()开销和内存碎片问题
但要注意:随机访问(get(int))是 O(n),远慢于 ArrayList 的 O(1)。别把它当普通列表用。
线程安全陷阱:LinkedList 本身不是线程安全的
即使你只用 push()/pop() 或 offer()/poll(),多个线程并发操作仍会破坏链表结构,导致 NullPointerException、无限循环或数据丢失。
常见错误写法:
LinkedListsharedStack = new LinkedList<>(); // ❌ 多线程下危险 // 线程 A 调用 push() // 线程 B 同时调用 pop() // 可能触发 ConcurrentModificationException 或静默损坏
正确做法:
- 用
Collections.synchronizedList(new LinkedList())—— 但仅同步单个方法,复合操作(如先isEmpty()再pop())仍需手动加锁 - 更推荐:栈用
Stack已过时,改用ArrayDeque+Collections.synchronizedDeque();队列优先选ConcurrentLinkedQueue或LinkedBlockingQueue
真正需要高性能并发栈/队列时,LinkedList 不是答案。










