CopyOnWriteArrayList:读多写少场景的列表
CopyOnWriteArrayList 是什么
写时复制策略:每次修改都复制全量数组,读取无需加锁。
java
// 读取时完全无锁
List<String> list = new CopyOnWriteArrayList<>();
list.get(0); // 无锁读取
list.size(); // 无锁读取写入时复制整个数组:
java
public boolean add(E e) {
synchronized (lock) {
Object[] newElements = Arrays.copyOf(elements, elements.length + 1);
newElements[elements.length] = e;
elements = newElements;
}
}vs ArrayList
| 特性 | ArrayList | CopyOnWriteArrayList |
|---|---|---|
| 线程安全 | ❌ | ✅ |
| 读性能 | 快 | 极快(无锁) |
| 写性能 | 快 | 慢(全量复制) |
| 迭代安全 | Fail-Fast | Fail-Safe |
| 内存开销 | 低 | 高(每次写都复制) |
典型应用场景
读多写少的配置列表
java
CopyOnWriteArrayList<Rule> rules = new CopyOnWriteArrayList<>();
// 高频读取规则
public List<Rule> getRules() {
return rules; // 返回快照,多线程读取无锁
}
// 偶尔修改规则
public void addRule(Rule rule) {
rules.add(rule);
}监听器列表
java
CopyOnWriteArrayList<Listener> listeners = new CopyOnWriteArrayList<>();
// 注册监听器(写操作)
public void addListener(Listener l) {
listeners.add(l);
}
// 触发监听器(读操作)
public void fireEvent(Event e) {
for (Listener l : listeners) {
l.onEvent(e); // 遍历时无锁
}
}常见问题
问题 1:写操作性能差
java
// ❌ 大数据量写操作性能极差
CopyOnWriteArrayList<List<String>> nested = new CopyOnWriteArrayList<>();
for (int i = 0; i < 10000; i++) {
nested.add(generateLargeList()); // 每次都复制全量数组
}
// 10000 次添加,复制了 1+2+3+...+10000 次 = 5000 万次元素拷贝问题 2:内存占用高
每次写操作都会产生新的数组副本,旧数组被 GC 回收前占用双份内存。
总结
| 要点 | 说明 |
|---|---|
| 读写特性 | 读极快(无锁),写极慢(全量复制) |
| 适用场景 | 读多写少(监听器列表、配置等) |
| 迭代安全 | Fail-Safe,遍历时无需同步 |
| 局限性 | 不适合写多场景,内存开销大 |
一句话:CopyOnWriteArrayList 是「读多写少」场景的列表,用全量复制换无锁读取。
