【问题标题】:Is there a drop-in replacement for Java Stack that is not synchronized?是否有不同步的 Java Stack 的替代品?
【发布时间】:2025-11-26 12:35:02
【问题描述】:

我有一个使用 Stack 数据结构的大型代码库(由我编写)。这是为了方便起见,我有时将其用作堆栈或向量/列表。

然而,经过性能评估,我们决定不为同步安全支付额外费用。我现在需要用非同步的结构替换这个结构(代码中多次提到)。

我很高兴地发现 Apache 集合包含一个 ArrayStack,这正是我想要的(与 Java 堆栈相同,但非同步)。但是,这没有像现代 Java 5 代码那样的泛型(这是我使用的)。而且我不会将我的代码转换成 Java 1.4 的样子

那么是否有任何其他符合 Java 5 的替代 Java Stack 或者我需要自己编写?

更新:

我将 LinkedList 与经过调整的“pop”/“push”方法一起使用。

【问题讨论】:

  • 就像 Jon Skeet 所说,ArrayDeque 是要走的路。顺便说一句,ArrayStack 在与 Stack 相同的意义上被破坏了,因为 ArrayStack 继承自 ArrayList,这是一个不好使用继承的好例子;-)。
  • 顺便说一句,如果您使用的是现代 HotSpot JVM,它很有可能已经为您优化了锁。例如,它已经使从StringBuffer(同步)到StringBuilder(非同步)的转换在很大程度上是不必要的(尽管它仍然有它的位置)。
  • @Adam 是的,我知道,但请尝试向客户解释!
  • @kazanaki:很公平。顺便问一下,你现在必须遵守的“绩效评估”是谁进行的?咨询公司?您是否知道他们是否衡量现有应用程序的性能以指导他们的建议?
  • @Adam 审查由客户执行。不要问...

标签: java data-structures stack


【解决方案1】:

当您说“符合 Java 5”时 - ArrayDeque<T> 直到 Java 6 才出现,但听起来像您所追求的(当然,在适当的情况下使用 Deque<T> 接口)。您可以在需要时将其用作堆栈,也可以将其用作更合适的队列……基本上只需调用适当的方法即可。

【讨论】:

  • 在 Java 5.0 中,您可以使用 LinkedList<E>add(0, E) 进行推送,使用 remove(0) 进行弹出。
  • @Peter:我同意。依赖具体类型只是一种耻辱。 :(
  • @Peter 我可能会照你说的做。如果您愿意,请将您的评论作为答案发表,以便我接受!否则 Jon Skeet 爵士将获得所有荣耀!
  • @Peter:我考虑过提到 LinkedList,但怀疑 OP 想要基于数组的解决方案的(部分)缓存一致性。但是是的,LinkedList 也可以。
  • @kazanaki,您可以使用 List 作为接口,因为它适用于任何列表。但是,要使 ArrayList 有效地工作,您必须从末尾添加/删除。 (这比使用 LinkedList 更快但更丑)add(e) 用于推送,remove(list.size()-1) 用于弹出。
【解决方案2】:

在您的特殊情况下(实际上仅在这种情况下),我只需将 Stack 类从开源 Java SE 实现中复制并粘贴到您自己的包中,然后删除所有同步的关键词。您可能需要添加extends java.util.Stack。现在您只需更改代码中的导入声明即可。

我确实意识到,通常复制代码不是一个好主意,但这就是为什么这不适用于这种情况:

  • 如果堆栈的pop()push() 语义非常适合当前代码,那么这不会仅仅因为性能考虑而改变。双端队列或链表的语义不同(它们允许从两侧添加/删除)。
  • java.util.Stack 的同步开销无法通过子类化(调用 super 方法)或委托等其他技术消除。
  • 最好复制经过良好测试的代码(在许可证允许的范围内),而不是从头开始重写。

一般情况下,将java.util.Stack当作接口使用会好很多,代码中不要使用new Stack(),而是使用工厂实例化它。

【讨论】:

  • 必须尊重版权。一般来说,复制代码是个坏主意,尤其是从 Oracle 复制代码:)而且它是一个“堆栈”,任何人都应该能够从头开始编写。
  • @irreputable:这就是为什么我明确地说“来自 开源 Java SE 实现”(我的意思是例如 Apache Harmony)。当然,仍然需要尊重许可证,但如果你这样做了,你可以复制它。
最近更新 更多