为什么Java Vector被认为是一个遗留类,过时或已弃用?

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

如果我不想手动同步对象,只是想使用线程安全的集合,而不需要使底层数组的新副本(如CopyOnWriteArrayList所做的),那么使用Vector是否很好?

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


当前回答

Vector对每个单独的操作进行同步。这几乎从来都不是你想做的。

通常,您希望同步整个操作序列。同步单个操作既不安全(例如,如果您迭代Vector,您仍然需要取出一个锁以避免其他人同时更改集合,这将在迭代线程中引起ConcurrentModificationException),也更慢(为什么要反复取出一个锁,一次就足够了)?

当然,即使在不需要锁定的情况下,它也有锁定的开销。

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

至于堆栈的等效——我会从Deque/ArrayDeque开始。

其他回答

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

Besides the already stated answers about using Vector, Vector also has a bunch of methods around enumeration and element retrieval which are different than the List interface, and developers (especially those who learned Java before 1.2) can tend to use them if they are in the code. Although Enumerations are faster, they don't check if the collection was modified during iteration, which can cause issues, and given that Vector might be chosen for its syncronization - with the attendant access from multiple threads, this makes it a particularly pernicious problem. Usage of these methods also couples a lot of code to Vector, such that it won't be easy to replace it with a different List implementation.

stack继承了java.util的同步开销。向量,这通常是不合理的。

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

出于这些性能和面向对象设计的原因,java.util.Stack的JavaDoc推荐ArrayDeque作为自然的替代品。(deque不仅仅是一个堆栈,但至少它被限制在操纵两端,而不是提供对所有东西的随机访问。)

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

1. 命名:Vector实际上只是可以作为数组访问的列表,所以它应该被称为ArrayList(这是Java 1.2集合对Vector的替代)。

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

数组列表和Vector之间没有太大的区别,但是你应该使用数组列表。

来自API文档。

从Java 2平台v1.2开始,这个 类进行了改造,以实现 列表接口,使其成为成员 Java集合框架。不像 新的集合实现, 矢量是同步的。

Vector对每个单独的操作进行同步。这几乎从来都不是你想做的。

通常,您希望同步整个操作序列。同步单个操作既不安全(例如,如果您迭代Vector,您仍然需要取出一个锁以避免其他人同时更改集合,这将在迭代线程中引起ConcurrentModificationException),也更慢(为什么要反复取出一个锁,一次就足够了)?

当然,即使在不需要锁定的情况下,它也有锁定的开销。

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

至于堆栈的等效——我会从Deque/ArrayDeque开始。