Java 的 CopyOnWriteArrayList 和 Collections.synchronizedList 有什么区别?分别有什么优缺点?

发布于:2025-03-17 ⋅ 阅读:(19) ⋅ 点赞:(0)

CopyOnWriteArrayList

问题:什么是 CopyOnWriteArrayList

解答

CopyOnWriteArrayList 是 Java 并发包 (java.util.concurrent) 提供的一种 线程安全List 实现,它的核心特性是 写时复制(Copy-On-Write)。即,每当执行修改操作(如 add()set()remove())时,都会创建 一个新的数组,修改操作会在这个新数组上进行,操作完成后再将新数组赋值给 CopyOnWriteArrayList 的内部变量。


核心特性

  1. 线程安全:由于读操作不需要加锁,多个线程可以并发访问,而写操作是通过复制新数组实现的,因此不会影响读取操作。
  2. 读写分离:读操作 (get()iterator()) 直接访问旧数组,不需要加锁;写操作 (add()set()remove()) 创建新数组,保证了读写的并发安全。
  3. 适用于读多写少的场景:由于写操作的成本较高(复制整个数组),CopyOnWriteArrayList 适合 读多写少 的应用场景,例如缓存、白名单、黑名单等。

源码分析

构造方法
public CopyOnWriteArrayList() {
   
    setArray(new Object[0]);
}

底层是一个 Object 数组,存储数据时会复制数组。

写操作

示例:add() 方法

public boolean add(E e) {
   
    final ReentrantLock lock = this.lock;
    lock.lock(); // 加锁保证写操作的线程安全
    try {
   
        Object[] elements = getArray();
        int len = elements.length;
        Object[] newElements = Arrays.copyOf(elements, len + 1); // 复制新数组
        newElements[len] = e;
        setArray(newElements); // 替换数组
        return true;
    } finally {
   
        lock.unlock();
    }
}

分析

  • 先获取当前数组 elements
  • 复制新数组 newElements,并将新元素放入其中。
  • setArray(newElements) 替换原数组,实现更新。
读操作

示例:get() 方法

public E get(int index) {
   
    return getArray(index);
}

分析

  • 直接读取数组,无需加锁,效率高。
遍历

CopyOnWriteArrayList 通过 iterator() 进行遍历:

public 

网站公告

今日签到

点亮在社区的每一天
去签到