多线程(34)CopyOnWriteArrayList

CopyOnWriteArrayList 是 Java 中一个线程安全的 ArrayList 变体,属于 java.util.concurrent 包。它通过在所有修改操作(如 add, set 等)上执行显式复制来实现线程安全。这种设计适用于列表读操作的数量远远大于写操作的场景。

设计原理

CopyOnWriteArrayList 的基本思想是,每当我们要修改列表的时候(添加、删除、设置等),不直接在当前的数组上进行操作,而是先将当前数组复制一份,然后在这个副本上进行修改。修改完成后,再将原来的数组引用指向新数组。这样做的好处是可以避免修改时阻塞读操作,读操作可以安全地访问数组,不需要加锁,因为对它们来说,数组从不改变。

结构解析

CopyOnWriteArrayList 内部维护了一个 volatile 的数组用来存储数据。由于使用了 volatile 关键字,它保证了数组内容的可见性。以下是一个简化的 CopyOnWriteArrayList 类的源码结构(基于 Java 8+),展示了其基本实现:

java 复制代码
// CopyOnWriteArrayList 源码片段(简化版本,基于 Java 8+)
class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, Serializable {
    // 确保可见性和禁止指令重排序
    private transient volatile Object[] array;

    // 获取底层数组的方法
    final Object[] getArray() {
        return array;
    }

    // 将数组设置为提供的数组
    final void setArray(Object[] a) {
        array = a;
    }

    // 添加元素的方法
    public boolean add(E e) {
        // 加锁以确保线程安全
        synchronized (this) {
            Object[] es = getArray();
            int len = es.length;
            // 复制出一个新数组
            es = Arrays.copyOf(es, len + 1);
            // 在新数组上操作
            es[len] = e;
            // 将原数组引用指向新数组
            setArray(es);
            return true;
        }
    }

    // 其他方法省略...
}

代码演示

下面是一个使用 CopyOnWriteArrayList 的简单示例:

java 复制代码
import java.util.concurrent.CopyOnWriteArrayList;

public class CopyOnWriteArrayListDemo {
    public static void main(String[] args) {
        CopyOnWriteArrayList<Integer> cowArrayList = new CopyOnWriteArrayList<>();

        // 示例:并发添加
        Thread thread1 = new Thread(() -> cowArrayList.add(1));
        Thread thread2 = new Thread(() -> cowArrayList.add(2));

        thread1.start();
        thread2.start();

        // 等待线程结束
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }

        // 迭代并打印结果
        for (Integer i : cowArrayList) {
            System.out.println(i);
        }
    }
}

总结

CopyOnWriteArrayList 提供了一种避免读写冲突的方法,非常适合读多写少的并发场景。它的优势是在进行遍历操作时不需要锁定,因此可以提高遍历操作的并发性能。但是,由于每次修改都需要复制整个底层数组,所以写操作的成本相对较高,特别是对于数据量大的列表。在选择使用 CopyOnWriteArrayList 之前,需要确保它适合你的应用场景。

相关推荐
铁皮饭盒15 小时前
这6个小模型各有绝活, 且都可cpu/浏览器端运行
前端·后端
qq_4069810316 小时前
大白话rust系列08 当变量遮蔽遇上引用,探究变量遮蔽的本质
开发语言·后端·rust
喵了几个咪16 小时前
GoWind ShortPlay 拆解:不用模型的推荐闭环——埋点回流、三路召回与已看去重
开发语言·后端·微服务·golang·gowind
SimonKing16 小时前
又找到一个纯Java的OCR项目,识别的格式还挺多
java·后端·程序员
程序猿DD17 小时前
OctaFuse Gateway 2.17.0:新增维护模式、请求日志汇总、DashScope 语音路由拆分
后端
陈随易18 小时前
副业搞钱点子之赛事与活动
前端·后端·程序员
Profile排查笔记18 小时前
有哪些开源指纹浏览器项目?先核对客户端、内核与许可证
前端·人工智能·后端·自动化
鶴哥只手遮天18 小时前
雷达系统与成像仿真:从电磁散射到工程实现-第 1 章 雷达系统的分层架构与指标闭环
后端
喵了几个咪18 小时前
GoWind UBA 拆解:把 Doris UNIQUE KEY 翻译成 ClickHouse——读数正确性对齐实录
开发语言·后端·clickhouse·微服务·golang·gowind
王中阳Go18 小时前
面试官问什么,取决于你简历上写了什么:后端转 Agent 岗的项目准备法
后端·面试·agent