• 同步性:Vector 是线程安全的,也就是说是同步的 ,而 ArrayList 是线程不安全的,不是同步的。
  • 数据增长:当需要增长时,Vector 默认增长为原来一倍 ,而 ArrayList 却是原来的 50% ,这样 ArrayList 就有利于节约内存空间。

说明:如果涉及到堆栈,队列等操作,应该考虑用 Vector,如果需要快速随机访问元素,应该使用 ArrayList

两条区别都对,但都停留在 JDK1.0 时代的认知。今天再谈 Vector,重点应是:为什么它被弃用、”线程安全”为什么名不副实、以及并发 List 的正确选型。

表面区别补全

维度 ArrayList Vector
同步 非同步 方法级 synchronized
扩容 1.5 倍 默认 2 倍(可配 capacityIncrement)
迭代器 Iterator fail-fast Iterator fail-fast + Enumeration(非 fail-fast)
出身 JDK1.2 集合框架 JDK1.0 遗留类
现状 默认选择 遗留兼容,新代码禁用

扩容差异的实质:2 倍扩容内存增长激进(浪费上限接近当前容量),1.5 倍更平滑但扩容次数略多;这是历史设计差异,不是优劣核心。

关键认知:Vector 的”线程安全”是残缺的

Vector 只保证单个方法调用原子(get、add 各自同步),但复合操作依然有竞态:

if (!vector.contains(x)) {   // 检查
vector.add(x); // 执行:两步之间可能被其他线程插入
}

两个线程同时通过 contains 检查后都 add,去重语义被破坏。这与 HashMap 包 synchronizedMap 的局限同源:方法级同步救不了 check-then-act。真正需要原子复合操作时,Vector 和 ArrayList 一样不合格。

此外 Vector 的同步是”全方法锁 this”:读读也互斥,多线程读场景吞吐崩塌;而现代并发结构(CopyOnWriteArrayList、并发队列)按读写特征细分同步策略。

并发 List 的正确选型

  • 读多写极少(配置缓存、监听器列表)→ CopyOnWriteArrayList:写时复制,读无锁无同步,迭代器快照不抛 CME
  • 读写都多 → 通常说明设计有问题;考虑分片、不可变替换(volatile 引用整体换)或并发 Map 替代
  • 队列语义 → ConcurrentLinkedQueue / LinkedBlockingQueue,而不是 List 加锁模拟
  • 单线程 → ArrayList,永远

“涉及堆栈、队列用 Vector”这句老说明也应更新:堆栈用 ArrayDeque(官方明确建议取代 Stack),队列用并发队列或 ArrayDeque,Vector 在任何新场景都没有位置。

遗留代码遇到 Vector 怎么办

  • 无并发需求:直接换 ArrayList(接口兼容,List 类型声明处无需改动)
  • 有并发但仅复合操作问题:换 CopyOnWriteArrayList 或在外层加业务锁保证复合原子
  • 依赖 Enumeration 的老 API:适配为 Iterator(enumeration.asIterator() 或 Collections.list)

Vector 的价值今天只剩一面镜子:它展示了”把 synchronized 加在每个方法上”这种粗糙并发设计的局限——安全是局部的、性能是全局牺牲的。理解这一点,比记住”Vector 同步、ArrayList 不同步”有用得多。