外观
一句话答案
写时复制:读无锁直接读数组,写加锁复制新数组修改后替换原数组,适合读多写少场景(如监听器列表)。
核心要点
核心原理:
- 读:无锁,直接读取内部
Object[] array(volatile 保证可见性) - 写:加 ReentrantLock → 复制底层数组 → 修改副本 → 替换原数组 → 释放锁
java
public boolean add(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] old = getArray();
Object[] newArr = Arrays.copyOf(old, old.length + 1);
newArr[old.length] = e;
setArray(newArr); // volatile 写
return true;
} finally { lock.unlock(); }
}优缺点:
- ✅ 读无锁,并发读性能极高
- ✅ 迭代器不会抛 ConcurrentModificationException
- ❌ 写操作慢(复制整个数组)
- ❌ 内存占用(写时两份数组)
- ❌ 数据弱一致性(读到旧数据)
适用场景: 事件监听器列表、配置项缓存(读远多于写)
追问与易错
追问方向:
- 写时复制的内存开销大吗?
- 迭代器是强一致还是弱一致?
- 什么场景适合用?
易错点:
- ❌ 写也是 O(1)——每次写复制整个数组 O(n)
- ❌ 在写多场景使用——性能极差
💡 记忆锚点
写时复制就像公告栏:读的人随便看不用排队,改的人先复印一份公告在副本上修改,改好后一次性换上去。代价是每次修改都要复印整张纸——所以只适合"看的人多、改的人少"的场景。