2024-03-23  阅读(0)
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://www.skjava.com/mianshi/baodian/detail/1325422357

回答

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] ,回复【面试题】 即可免费领取。

阅读全文