copyonwritearraylist通过读写分离、volatile引用和原子替换实现线程安全:读操作无锁且可见,写操作加锁复制替换,迭代器基于快照避免并发修改异常。

CopyOnWriteArrayList 通过“写时复制”(Copy-On-Write, COW)机制,在不阻塞读操作的前提下,实现线程安全。它的安全不是靠锁住整个读过程,而是靠**读写分离 + volatile 引用 + 原子替换**三者协同完成。
读操作完全无锁,靠 volatile 保证可见性
底层用一个 volatile Object[] array 存储元素。volatile 关键字确保:
- 任意线程对 array 引用的更新(比如写操作后指向新数组),对其他线程立即可见;
- 读线程调用 get(int index) 时,直接访问当前 array 的指定下标,不加锁、不校验、不阻塞;
- 多个读线程可并发执行,互不影响,性能接近普通 ArrayList。
写操作加锁 + 复制 + 替换,保证修改原子性
所有写操作(add、remove、set)都遵循统一流程:
- 先获取 ReentrantLock lock,确保同一时刻只有一个线程能进入写逻辑;
- 调用 Arrays.copyOf() 复制当前 array,生成新数组(长度±1);
- 在新数组上完成增删改,原数组保持不变;
- 调用 setArray(newElements),用 volatile 写入新引用,原子替换旧数组。
迭代器基于快照,天然避免并发修改异常
调用 iterator() 时,会捕获当前 array 的引用并封装进迭代器。此后:
- 迭代器始终遍历创建那一刻的数组副本,不受后续写操作影响;
- 即使其他线程正在 add 或 remove,该迭代器也不会抛 ConcurrentModificationException;
- 迭代结果反映的是“某一时刻的快照”,属于弱一致性语义,适合配置、监听器等场景。
关键设计点总结
- volatile 数组引用是读写同步的桥梁,不是保护数组内容,而是保证新数组“一换即见”;
- ReentrantLock 只锁写操作入口,不锁读,也不锁整个数组生命周期;
- 每次写都产生新数组,旧数组对读线程仍有效,直到被 GC 回收;
- 没有“中间态”——读线程要么看到旧数组全貌,要么看到新数组全貌,不会看到半新半旧的数据。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











