ArrayList 不支持并发读写分离,因其非线程安全,多线程读写会导致 ConcurrentModificationException、数据丢失或 size 错误;推荐使用 CopyOnWriteArrayList 实现读写分离,它通过写时复制保障读操作无锁、不抛异常,但写操作开销大且不支持复合原子操作。

Java 中 ArrayList 本身不支持并发读写分离,它不是线程安全的集合类,任何并发读写都可能导致 ConcurrentModificationException、元素丢失或 size 错误。要实现真正的读写分离,必须换用专门设计的线程安全替代方案,而非对 ArrayList 加锁封装。
为什么不能直接用 ArrayList 做读写分离
ArrayList 的 add、remove 等操作不是原子的:先检查容量、再扩容、再复制、最后赋值。多线程同时触发扩容,可能各自创建新数组并覆盖引用,造成数据静默丢失;迭代器又依赖 modCount 做 fail-fast 检查,一旦有线程修改结构,正在遍历的线程立刻抛异常。这不是 bug,而是设计使然——它本就不为并发而生。
推荐方案:CopyOnWriteArrayList(读多写少首选)
这是 JDK java.util.concurrent 包中专为读写分离设计的列表,底层采用“写时复制”机制:
- 所有读操作(
get()、contains()、增强 for 循环、iterator())完全无锁,直接访问当前数组快照 - 每次写操作(
add()、remove()、set())都会新建数组,复制原内容,在副本上修改,再用 volatile 引用原子替换 - 正在读取的线程不受写操作影响,不会抛
ConcurrentModificationException - 适合配置列表、监听器注册表、黑白名单等启动后极少更新、但被高频读取的场景
其他可行方案及适用边界
若场景不满足“读远多于写”,需按需选择:
立即学习“Java免费学习笔记(深入)”;
- Collections.synchronizedList(new ArrayList()):读写均加同一把互斥锁,简单但吞吐低,读操作也被阻塞,无法真正分离
- Vector:历史遗留类,方法基本都 synchronized,性能更差,且不推荐在新代码中使用
- 手动分段加锁 + ArrayList:复杂度高、易出错,仅在极特殊优化需求下考虑,一般没必要
- 读写锁(ReentrantReadWriteLock)包裹 ArrayList:可实现读共享、写独占,但需自行管理锁粒度和迭代安全,仍无法避免 fail-fast,且写操作期间读请求会排队
使用 CopyOnWriteArrayList 的关键提醒
它不是万能药,要注意这些限制:
- 写操作开销大:每次增删都要复制整个数组,大数据量或高频写入会导致 GC 压力和延迟飙升
- 不支持复合原子操作:比如“先检查再添加”需额外同步,否则存在竞态(
if (!list.contains(x)) list.add(x)不是原子的) - 迭代器返回的是快照,无法反映写操作的实时结果;新增元素对当前迭代不可见
- 不允许存
null元素(调用 add(null) 会抛NullPointerException)


















