为什么Java Vector被认为是遗留类,已过时或已弃用?
在使用并发时,它的使用是否有效?
如果我不想手动同步对象并且只想使用线程安全的集合而不需要创建底层数组的新副本(如 CopyOnWriteArrayList 那样),那么使用 Vector 是否可以?
CopyOnWriteArrayList
Vector
那么 Stack ,它是 Vector 的一个子类,我应该用它来代替它?
Stack
您可以使用 java.util.Collection 上的synchronizedCollection/List方法从非线程安全集合中获取线程安全集合 .
java.util.Collection
Vector是1.0的一部分 - 原始实现有两个缺点:
1. Naming: 向量实际上只是可以作为数组访问的列表,因此它应该被称为 ArrayList (这是 Vector 的Java 1.2 Collections替代品) .
ArrayList
2. Concurrency: 所有 get() , set() 方法都是 synchronized ,因此您无法对同步进行细粒度控制 .
get()
set()
synchronized
ArrayList 和 Vector 之间没有太大区别,但您应该使用 ArrayList .
来自API文档 .
从Java 2平台v1.2开始,这个类被改进以实现List接口,使其成为Java Collections Framework的成员 . 与新的集合实现不同,Vector是同步的 .
Vector 在每个单独的操作上同步 . 这几乎不是你想要做的 .
通常,您希望同步整个操作序列 . 同步单个操作既不安全(例如,如果你迭代 Vector ,你仍然需要取出一个锁来避免其他人同时更改集合,这会在迭代线程中导致 ConcurrentModificationException )而且慢一点(为什么一旦足够就反复取出锁)?
ConcurrentModificationException
当然,即使你不需要,它也有锁定的开销 .
基本上,在大多数情况下,这是一种非常有缺陷的同步方法 . 正如 Mr Brian Henk 指出的那样,你可以使用Collections.synchronizedList之类的调用来修饰集合 - Vector 将"resized array"集合实现与"synchronize every operation"位结合起来的事实是另一个糟糕设计的例子;装饰方法可以更清晰地分离顾虑 .
至于 Stack 等价物 - 我会先看 Deque / ArrayDeque .
Deque
ArrayDeque
java.util.Stack 继承了 java.util.Vector 的同步开销,这通常是不合理的 .
java.util.Stack
java.util.Vector
不过,它继承了很多东西 . 事实上 java.util.Stack extends java.util.Vector 在面向对象设计中是一个错误 . 纯粹主义者会注意到它除了传统上与堆栈相关的操作之外还提供了许多方法(即:push,pop,peek,size) . 也可以执行 search , elementAt , setElementAt , remove 和许多其他随机访问操作 . 基本上由用户决定不使用 Stack 的非堆栈操作 .
java.util.Stack extends java.util.Vector
search
elementAt
setElementAt
remove
对于这些性能和OOP设计的原因,JavaDoc for java.util.Stack建议ArrayDeque作为自然替代品 . (deque不仅仅是一个堆栈,但至少它仅限于操纵两端,而不是随机访问所有内容 . )
除了已经陈述的关于使用Vector的答案之外,Vector还有一些围绕枚举和元素检索的方法,这些方法与List接口不同,开发人员(特别是那些在1.2之前学习Java的人)可以倾向于使用它们,如果他们在码 . 尽管Enumerations速度更快,但它们不会检查集合是否在迭代期间被修改,这可能会导致问题,并且考虑到可能会选择Vector进行同步 - 通过多个线程的伴随访问,这使得它成为一个特别有害的问题 . 这些方法的使用也将大量代码耦合到Vector,因此用不同的List实现替换它并不容易 .
5 回答
您可以使用
java.util.Collection
上的synchronizedCollection/List方法从非线程安全集合中获取线程安全集合 .Vector是1.0的一部分 - 原始实现有两个缺点:
1. Naming: 向量实际上只是可以作为数组访问的列表,因此它应该被称为
ArrayList
(这是Vector
的Java 1.2 Collections替代品) .2. Concurrency: 所有
get()
,set()
方法都是synchronized
,因此您无法对同步进行细粒度控制 .ArrayList
和Vector
之间没有太大区别,但您应该使用ArrayList
.来自API文档 .
Vector
在每个单独的操作上同步 . 这几乎不是你想要做的 .通常,您希望同步整个操作序列 . 同步单个操作既不安全(例如,如果你迭代
Vector
,你仍然需要取出一个锁来避免其他人同时更改集合,这会在迭代线程中导致ConcurrentModificationException
)而且慢一点(为什么一旦足够就反复取出锁)?当然,即使你不需要,它也有锁定的开销 .
基本上,在大多数情况下,这是一种非常有缺陷的同步方法 . 正如 Mr Brian Henk 指出的那样,你可以使用Collections.synchronizedList之类的调用来修饰集合 -
Vector
将"resized array"集合实现与"synchronize every operation"位结合起来的事实是另一个糟糕设计的例子;装饰方法可以更清晰地分离顾虑 .至于
Stack
等价物 - 我会先看Deque
/ArrayDeque
.java.util.Stack
继承了java.util.Vector
的同步开销,这通常是不合理的 .不过,它继承了很多东西 . 事实上
java.util.Stack extends java.util.Vector
在面向对象设计中是一个错误 . 纯粹主义者会注意到它除了传统上与堆栈相关的操作之外还提供了许多方法(即:push,pop,peek,size) . 也可以执行search
,elementAt
,setElementAt
,remove
和许多其他随机访问操作 . 基本上由用户决定不使用Stack
的非堆栈操作 .对于这些性能和OOP设计的原因,JavaDoc for java.util.Stack建议ArrayDeque作为自然替代品 . (deque不仅仅是一个堆栈,但至少它仅限于操纵两端,而不是随机访问所有内容 . )
除了已经陈述的关于使用Vector的答案之外,Vector还有一些围绕枚举和元素检索的方法,这些方法与List接口不同,开发人员(特别是那些在1.2之前学习Java的人)可以倾向于使用它们,如果他们在码 . 尽管Enumerations速度更快,但它们不会检查集合是否在迭代期间被修改,这可能会导致问题,并且考虑到可能会选择Vector进行同步 - 通过多个线程的伴随访问,这使得它成为一个特别有害的问题 . 这些方法的使用也将大量代码耦合到Vector,因此用不同的List实现替换它并不容易 .