vector 的 add() 和 get() 天然线程安全,因其关键方法均用 synchronized 修饰,独占对象锁,保证单操作原子性与可见性,但不保障复合操作安全,且迭代时仍可能抛 concurrentmodificationexception。

Vector 的 add() 和 get() 为什么天然线程安全
因为 Vector 的关键方法(如 add()、get()、remove())默认用 synchronized 修饰,每个方法调用都独占整个对象锁。这意味着:同一时刻只能有一个线程执行任意一个同步方法,天然避免了并发修改导致的 ConcurrentModificationException 或数据错乱。
但要注意:这种粗粒度锁只保单个操作原子性,不保复合操作。比如“检查是否存在再添加”这种 if (!v.contains(x)) v.add(x); 仍需外部加锁,否则中间可能被其他线程插入相同元素。
-
Vector的elementData数组本身非 volatile,但所有访问都经同步块,所以可见性由锁保证,不是靠内存屏障 - 和
ArrayList不同,Vector默认扩容因子是 1.0(即翻倍),且扩容过程也在同步块内完成,不会出现数组引用更新与长度更新不同步的问题 - 不要误以为
synchronized方法能防止迭代时的并发修改——Iterator仍是 fail-fast 的,遍历时其他线程调用add()仍会抛ConcurrentModificationException
为什么 Enumeration 比 Iterator 更“配合” Vector 的同步机制
Vector 提供的 elements() 返回 Enumeration,而它所有方法(hasMoreElements()、nextElement())本身不加锁,也不校验 modCount。这看似危险,实则是设计取舍:在纯同步上下文中,用 Enumeration 遍历不会触发 fail-fast,因为它的实现直接读 elementData 和 elementCount,而这两个字段的读写都被包裹在 Vector 的同步方法里,天然有序。
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
- 用
Iterator遍历时,即使外层已用synchronized(v) { ... }包裹,内部Iterator仍会记录初始modCount,一旦其他线程调用同步方法修改结构,下次next()就抛异常 -
Enumeration没有这个检查,适合老式代码中“边遍历边允许其他线程增删”的场景(但需自行控制逻辑正确性) - JDK 1.2 引入
Iterator后,Vector的iterator()方法返回的是带 fail-fast 的迭代器,和Enumeration是两套并存机制
Vector 与 Collections.synchronizedList() 的关键差异
两者都提供线程安全列表,但实现层级不同:Vector 是类级别同步,而 Collections.synchronizedList(new ArrayList()) 是装饰器模式,所有方法委托给底层 ArrayList 并在方法入口加 synchronized(this)。
- 行为上几乎一致,但
Vector的size()、isEmpty()等读方法也同步,而装饰器的对应方法同样同步——这点常被忽略,误以为“读操作不用锁” -
Vector支持序列化时自动处理同步状态(writeObject方法内同步整个写过程),而装饰器的序列化不保证线程安全,若序列化过程中有其他线程修改,可能抛ConcurrentModificationException - 性能上无本质优势:都是全对象锁,高并发下吞吐量远低于
CopyOnWriteArrayList或ConcurrentHashMap
现代开发中还该用 Vector 吗
基本不该。JDK 5 引入 java.util.concurrent 包后,Vector 就被明确标记为遗留类。它的同步策略太重,无法支持分段锁、CAS 等优化,且 API 设计(如 addElement() 和 add() 并存)已过时。
- 替代方案优先选
CopyOnWriteArrayList(读多写少)、ConcurrentLinkedQueue(无锁队列)、或ConcurrentHashMap(需要键值语义时) - 如果只是临时需要线程安全包装,用
Collections.synchronizedList()比Vector更清晰,因为它不隐藏“这是个装饰器”的事实 - 真正要理解线程安全集合的演进,重点不在
Vector的实现细节,而在它暴露的问题:粗粒度锁 → 迭代与修改冲突 → 读写分离需求 → 无锁算法探索
现在看 Vector,更像是一个教科书式的反例:它证明了“加 synchronized 就线程安全”这句话,只对单个操作成立,而真实业务里的临界区往往跨多个调用。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










