Java中栈的多种实现类详解
Java中栈的多种实现类详解:Stack、LinkedList与ArrayDeque全方位对比
- 前言
- 一、Stack类——Java最早的栈实现
- 1.1 Stack类简介
- 1.2 常用方法
- 1.3 优缺点分析
- 二、LinkedList类——灵活的双端链表
- 2.1 LinkedList类简介
- 2.2 常用方法
- 2.3 优缺点分析
- 三、ArrayDeque类——高性能的现代选择
- 3.1 ArrayDeque类简介
- 3.2 常用方法
- 3.3 优缺点分析
- 四、三者方法对比
- 五、代码实现
- 5.1 Stack实现
- 5.2 LinkedList实现
- 5.3 ArrayDeque实现
- 六、线程安全与高并发场景下的栈实现
- 6.1 Stack的线程安全
- 6.2 ArrayDeque/LinkedList的线程安全处理
- 6.3 高并发场景下的栈实现
- 七、总结与最佳实践
- 参考资料
前言
在日常开发和算法题中,栈(Stack)是一种非常常用的数据结构,它遵循“后进先出(LIFO)”的原则,常用于括号匹配、表达式求值、递归模拟等场景。那么在Java中,我们该如何选择合适的栈实现类?本文我将详细分析Java中三种常见的栈实现方式:Stack
、LinkedList
、ArrayDeque
,并通过原理对比它们的优缺点,最后探讨在多线程/高并发场景下的栈实现方案。
一、Stack类——Java最早的栈实现
1.1 Stack类简介
Stack
类是Java 1.0就引入的栈实现,位于java.util
包下。它继承自Vector
,本质上是一个线程安全的动态数组。
1.2 常用方法
Stack<Integer> stack = new Stack<>();
stack.push(1); // 入栈
stack.push(2);
int top = stack.pop(); // 出栈,返回2
int peek = stack.peek(); // 查看栈顶元素,不移除
boolean empty = stack.empty(); // 判断栈是否为空
int pos = stack.search(1); // 查找元素,返回距离栈顶的偏移量
1.3 优缺点分析
优点:
- 直接实现了栈的常用操作,API简单易用。
- 线程安全,所有方法都加了
synchronized
。
缺点:
- 继承自
Vector
,设计上有历史包袱,方法和结构不够现代化。 - 线程安全带来的同步开销,单线程下性能较差。
- Java官方已不推荐新代码使用,属于遗留类(legacy class)。
二、LinkedList类——灵活的双端链表
2.1 LinkedList类简介
LinkedList
实现了Deque
接口,可以作为栈、队列、双端队列使用。底层是双向链表结构。
2.2 常用方法
LinkedList<Integer> stack = new LinkedList<>();
stack.push(1); // 入栈
stack.push(2);
int top = stack.pop(); // 出栈,返回2
int peek = stack.peek(); // 查看栈顶元素,不移除
boolean empty = stack.isEmpty(); // 判断栈是否为空
注意:
LinkedList
的push
/pop
/peek
方法其实是Deque
接口的方法,等价于addFirst
/removeFirst
/getFirst
。
2.3 优缺点分析
优点:
- 实现了
Deque
接口,方法丰富,既能做栈也能做队列。 - 插入和删除操作效率高(O(1)),适合频繁增删。
- 灵活性高,支持双端操作。
缺点:
- 不是线程安全的。
- 每个节点有额外的指针开销,内存占用比数组大。
- 访问元素时需要遍历链表,随机访问性能差。
三、ArrayDeque类——高性能的现代选择
3.1 ArrayDeque类简介
ArrayDeque
同样实现了Deque
接口,底层用循环数组实现。它是Java官方推荐的栈/队列实现。
3.2 常用方法
ArrayDeque<Integer> stack = new ArrayDeque<>();
stack.push(1); // 入栈
stack.push(2);
int top = stack.pop(); // 出栈,返回2
int peek = stack.peek(); // 查看栈顶元素,不移除
boolean empty = stack.isEmpty(); // 判断栈是否为空
注意:
ArrayDeque
不能存储null
元素,否则会抛出NullPointerException
。
3.3 优缺点分析
优点:
- 实现了
Deque
接口,方法丰富,既能做栈也能做队列。 - 基于数组,内存利用率高,局部性好,性能优于
LinkedList
。 - 没有同步开销,单线程下性能最好。
- 支持栈和队列操作,灵活性高。
缺点:
- 不是线程安全的。
- 数组需要扩容时有一定的性能开销。
- 不能存储
null
元素。
四、三者方法对比
方法/类 | Stack | LinkedList | ArrayDeque |
---|---|---|---|
push(E e) | 有 | 有 | 有 |
pop() | 有 | 有 | 有 |
peek() | 有 | 有 | 有 |
empty()/isEmpty() | 有 | 有 | 有 |
search(Object o) | 有 | 无 | 无 |
线程安全 | 是 | 否 | 否 |
支持null元素 | 是 | 是 | 否 |
随机访问 | 支持 | 不支持 | 不支持 |
性能 | 较低 | 一般 | 最优 |
五、代码实现
5.1 Stack实现
Stack<Integer> stack = new Stack<>();
stack.push(10);
stack.push(20);
System.out.println(stack.pop()); // 20
System.out.println(stack.peek()); // 10
System.out.println(stack.empty()); // false
5.2 LinkedList实现
LinkedList<Integer> stack = new LinkedList<>();
stack.push(10);
stack.push(20);
System.out.println(stack.pop()); // 20
System.out.println(stack.peek()); // 10
System.out.println(stack.isEmpty()); // false
5.3 ArrayDeque实现
ArrayDeque<Integer> stack = new ArrayDeque<>();
stack.push(10);
stack.push(20);
System.out.println(stack.pop()); // 20
System.out.println(stack.peek()); // 10
System.out.println(stack.isEmpty()); // false
六、线程安全与高并发场景下的栈实现
6.1 Stack的线程安全
Stack
类的所有方法都加了synchronized
,天然线程安全。但由于同步粒度较粗,性能较低,不适合高并发场景。
6.2 ArrayDeque/LinkedList的线程安全处理
这两者本身不是线程安全的,如果在多线程环境下使用,可以通过Collections.synchronizedDeque
进行包装:
Deque<Integer> safeStack = Collections.synchronizedDeque(new ArrayDeque<>());
safeStack.push(1);
safeStack.push(2);
System.out.println(safeStack.pop());
6.3 高并发场景下的栈实现
如果你需要在高并发场景下使用栈,推荐使用并发包下的实现:
ConcurrentLinkedDeque
:高并发下的无界线程安全双端队列,可以作为栈使用。
Deque<Integer> concurrentStack = new ConcurrentLinkedDeque<>();
concurrentStack.push(1);
concurrentStack.push(2);
System.out.println(concurrentStack.pop());
BlockingDeque
:支持阻塞操作的双端队列,适合生产者-消费者场景。
BlockingDeque<Integer> blockingStack = new LinkedBlockingDeque<>();
blockingStack.push(1);
blockingStack.push(2);
System.out.println(blockingStack.pop());
七、总结与最佳实践
- 单线程场景:优先推荐
ArrayDeque
,性能最好,API丰富。 - 需要线程安全:用
Collections.synchronizedDeque(new ArrayDeque<>())
或ConcurrentLinkedDeque
。 - 老代码维护:
Stack
可以用,但不推荐新项目使用。 - 特殊需求:如需要阻塞、限界等功能,选择
BlockingDeque
相关实现。
参考资料
- Java官方文档 - Stack
- Java官方文档 - ArrayDeque
- Java官方文档 - LinkedList
若这篇内容帮到你,动动手指支持下!关注不迷路,干货持续输出!
ヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノヾ(´∀ ˋ)ノ