回答
CopyOnWriteArrayList
是一个线程安全的 ArrayList,其核心思想是“写时复制”,即每当我们对列表进行修改(添加、删除、更新元素)时,它都会先创建该列表的一个副本,然后在这个副本上进行修改。修改完成后,它会将原来的列表引用指向新修改过的副本。这种机制有效减少了线程之间的竞争,因为读操作可以安全地访问列表,而不需要担心写操作同时发生的情况。
copy-on-Write 体现的是一种读写分离的思想。
CopyOnWriteArrayList 实现原理
原理
写时复制原理图:
CopyOnWriteArrayList
的实现原理比较简单,源码也很简单,我们大致看下就可以了。
- 结构
CopyOnWriteArrayList
使用一个 volatile 类型的数组来存储数据,volatile 保证这个数组引用的可见性,当数组发生变化时,其他所有线程都能立即看到这个变化。
private transient volatile Object[] array;
同时为了保证线程安全,CopyOnWriteArrayList
新建了一个 Object 锁对象。
final transient Object lock = new Object();
- 添加元素
当我们需要添加一个元素时,CopyOnWriteArrayList
会先锁定整个类(利用 object 锁对象),然后复制一个新的数组,大小为原数组大小加 1,然后将新元素添加到新数组的末尾,最后再将引用指向新的数组。
public boolean add(E e) {
synchronized (lock) {
Object[] es = getArray();
int len = es.length;
es = Arrays.copyOf(es, len + 1);
es[len] = e;
setArray(es);
return true;
}
}
这里为什么只 + 1 呢?因为 CopyOnWriteArrayList
的使用场景是读多写少的场景,旨在优化读操作,选择牺牲了写的性能。只 + 1 的原因是为了减少内存占用和复制成本。如果每次增加的空间过多,将导致不必要的内存浪费,特别是在元素添加不频繁的情况下。有小伙伴说,多加点又如何呢?多加点说明你写的场景有点儿多,这个时候你要考虑的就不是 CopyOnWriteArrayList
了。
- 读取元素
CopyOnWriteArrayList
旨在优化读操作,所以读取是无锁的。由于所有的修改操作都会创建一个新的数组,所以不会出现并发问题。
public E get(int index) {
return elementAt(getArray(), index);
}
缺点
- 内存占用和复制开销:
CopyOnWriteArrayList
在每次修改时都需要复制整个列表,这可能会导致较高的内存占用和复制开销。因此,如果列表较大或者写操作频繁,CopyOnWriteArrayList
可能不是好的选择。 - 数据一致性问题::
CopyOnWriteArrayList
提供的迭代器是弱一致性的。这意味着在遍历元素时是基于列表的某个固定版本进行的,即使后续有修改操作,迭代器看到的内容也不会改变。
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。