717

为什么 Java Vector 被视为遗留类、已过时或已弃用?

处理并发时它的使用是否有效?

如果我不想手动同步对象并且只想使用线程安全集合而不需要制作底层数组的新副本(就像CopyOnWriteArrayList那样),那么可以使用Vector吗?

怎么样Stack,它是 的子类Vector,我应该用什么来代替它?

4

5 回答 5

694

Vector同步每个单独的操作。这几乎不是你想做的。

通常,您希望同步整个操作序列。同步单个操作既不安全(例如,如果您迭代 a Vector,您仍然需要取出锁以避免其他任何人同时更改集合,这会导致 aConcurrentModificationException在迭代线程中)而且速度较慢(一次就够了,为什么要反复拔锁)?

当然,即使您不需要,它也有锁定的开销。

基本上,在大多数情况下,这是一种非常有缺陷的同步方法。正如Brian Henk 先生指出的那样,您可以使用以下调用来装饰集合Collections.synchronizedList- 将“调整大小的数组”集合实现与“同步每个操作”位相结合的事实Vector是设计不佳的另一个例子;装饰方法提供了更清晰的关注点分离。

至于Stack等价物 - 我会从Deque/ArrayDeque开始。

于 2009-09-06T18:07:44.517 回答
87

Vector 是 1.0 的一部分——最初的实现有两个缺点:

1. 命名:向量实际上只是可以作为数组访问的列表,因此应该调用它ArrayList(这是 Java 1.2 Collections 的替代品Vector)。

2. 并发:所有的get(),set()方法都是synchronized,所以你不能对同步进行细粒度的控制。

ArrayList和之间没有太大区别Vector,但您应该使用ArrayList.

来自 API 文档。

从 Java 2 平台 v1.2 开始,该类被改进为实现 List 接口,使其成为 Java Collections Framework 的成员。与新的集合实现不同,Vector 是同步的。

于 2009-09-06T18:12:31.793 回答
42

除了已经说明的关于使用 Vector 的答案外,Vector 还有一堆与 List 接口不同的枚举和元素检索方法,开发人员(尤其是那些在 1.2 之前学习 Java 的人)可以倾向于使用它们,如果他们在代码。尽管枚举更快,但它们不会检查集合是否在迭代期间被修改,这可能会导致问题,并且考虑到可能会选择 Vector 进行同步 - 伴随着来自多个线程的访问,这使得它成为一个特别有害的问题。这些方法的使用也将大量代码与 Vector 耦合,因此不容易用不同的 List 实现替换它。

于 2009-09-06T20:53:26.227 回答
15

您可以使用synchronizedCollection/List方法java.util.Collection从非线程安全的集合中获取线程安全的集合。

于 2009-09-06T18:07:36.763 回答
9

java.util.Stack继承 的同步开销java.util.Vector,这通常是不合理的。

不过,它继承的远不止这些。这java.util.Stack extends java.util.Vector是面向对象设计中的一个错误。纯粹主义者会注意到,除了传统上与堆栈相关的操作(即:push、pop、peek、size)之外,它还提供了许多方法。也可以执行search, elementAt, setElementAt,remove和许多其他随机访问操作。基本上由用户来避免使用Stack.

由于这些性能和 OOP 设计原因,JavaDoc 被java.util.Stack推荐ArrayDeque为自然替代品。(双端队列不仅仅是一个堆栈,但至少它仅限于操作两端,而不是提供对所有内容的随机访问。)

于 2016-02-12T21:04:52.770 回答