Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • MacOS
  • Linux
  • Windows
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • MacOS
  • Linux
  • Windows
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java基础

    • Java概述
    • Java语法
    • 面向对象编程
    • Java数组
    • String字符串
    • 异常处理
  • Java集合

    • Java集合概述
    • ArrayList
    • LinkedList
    • HashMap
    • LinkedHashMap
    • HashSet
    • TreeMap
    • Queue&Deque
  • Java并发

    • Java并发概述
    • 线程与进程
    • Thread类与线程生命周期
    • 线程安全
    • synchronized关键字
    • volatile关键字
    • Java内存模型(JMM)
    • 线程间通信
    • 线程池
    • 并发工具类
    • 原子操作类Atomic
    • 并发锁
    • 并发容器
    • ConcurrentHashMap
    • BlockingQueue
    • CopyOnWriteArrayList
      • 1. CopyOnWriteArrayList 的基本概念
      • 2. CopyOnWriteArrayList 的特性
      • 3. CopyOnWriteArrayList 的实现原理
        • 3.1 添加元素
        • 3.2 读取元素
        • 3.3 迭代器实现
      • 4. CopyOnWriteArrayList 的应用场景
      • 5. 优缺点分析
      • 6. 总结
    • ThreadLocal
    • Fork/Join框架
    • ScheduledThreadPoolExecutor
    • CompletableFuture
  • Java IO

    • Java IO概述
  • JVM

    • JVM概述
  • Java
  • Java并发
Wray
2024-10-31
目录

CopyOnWriteArrayList

CopyOnWriteArrayList 是 Java 中一种线程安全的 List 实现,适用于多线程环境下需要频繁读取且写操作较少的场景。它通过在写操作时复制整个底层数组来确保线程安全,因而在写操作较少时可以提供非常高效的读取性能。

# 1. CopyOnWriteArrayList 的基本概念

  • 线程安全性:CopyOnWriteArrayList 通过在修改操作时复制底层数组来实现线程安全,这意味着在进行插入、删除等修改操作时,创建一个新的数组并将旧数组的数据复制到新数组中。
  • 读写分离:读取操作和写入操作互不影响。读取操作直接访问当前数组,而写入操作则创建一个新的数组,保证了在读取时不会发生数据竞争。
  • 不可变性:由于每次写操作都会生成一个新的数组,所以对 CopyOnWriteArrayList 的读取操作是不可变的,这在一定程度上提高了安全性。

# 2. CopyOnWriteArrayList 的特性

  • 高效读操作:由于读操作不需要加锁,可以实现非常高效的并发读,这使得 CopyOnWriteArrayList 特别适用于读多写少的场景。
  • 写时开销大:每次写入操作(如添加、删除)都会复制整个数组,这对于频繁修改的场景来说代价非常高,因此不适合写操作频繁的应用场景。
  • 迭代器的弱一致性:CopyOnWriteArrayList 提供的迭代器是弱一致性的,这意味着迭代器不会抛出 ConcurrentModificationException,并且可以容忍在迭代过程中对列表的修改,但不会反映出最新的修改。

# 3. CopyOnWriteArrayList 的实现原理

CopyOnWriteArrayList 的核心思想是在修改时进行数组复制,下面我们详细分析其源码实现的关键部分。

# 3.1 添加元素

  • add(E e) 方法:在添加元素时,CopyOnWriteArrayList 会创建一个新的数组,并将现有元素复制到新数组中,然后在末尾添加新元素,最后将内部数组引用指向新的数组。
    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();
        }
    }
    
    • 在 add 方法中,首先获取锁以确保线程安全,然后复制原始数组并添加新元素,最后将新的数组设置为内部数据结构。

# 3.2 读取元素

  • get(int index) 方法:读取元素时直接从底层数组中获取数据,无需加锁。
    public E get(int index) {
        return getArray(index);
    }
    
    • 由于底层数组在写入时会被复制,所以读取操作是线程安全的,不需要额外的同步控制。

# 3.3 迭代器实现

  • 弱一致性:CopyOnWriteArrayList 提供的迭代器基于数组的快照创建,迭代器遍历期间的修改不会反映在迭代器中。
    public Iterator<E> iterator() {
        return new COWIterator<>(getArray(), 0);
    }
    
    • COWIterator 是基于底层数组的快照实现的,因此即使在迭代过程中对列表进行了修改,迭代器仍然可以正常工作,但不会看到最新的更改。

# 4. CopyOnWriteArrayList 的应用场景

  • 读多写少:CopyOnWriteArrayList 非常适用于读操作频繁而写操作较少的场景,例如:
    • 配置管理:系统中的配置项通常是读多写少,CopyOnWriteArrayList 可以确保配置项在读取时的高效性。
    • 监听器列表:在事件监听机制中,监听器列表通常会被频繁读取(通知事件),但添加或删除监听器的操作相对较少。
  • 防止 ConcurrentModificationException:CopyOnWriteArrayList 的迭代器不会抛出 ConcurrentModificationException,适用于需要在迭代时进行增删操作的场景。

# 5. 优缺点分析

  • 优点:
    • 线程安全:通过复制数组实现线程安全,读操作不需要加锁,确保高效读取。
    • 无 ConcurrentModificationException:迭代器不会因并发修改抛出异常,提供了一种简洁的线程安全迭代方式。
  • 缺点:
    • 写操作开销大:每次修改都会复制整个数组,导致写操作的性能较低,特别是在列表较大时。
    • 内存消耗:由于每次写操作都会创建一个新的数组,内存消耗较大,不适合内存紧张的环境。

# 6. 总结

CopyOnWriteArrayList 是 Java 并发编程中一种特殊的线程安全列表实现,适用于读操作多而写操作少的场景。它通过在修改时复制数组来实现线程安全,从而在多线程环境中提供了高效的读取性能。理解其内部机制和应用场景,可以帮助开发者在合适的场景中使用 CopyOnWriteArrayList,提高并发程序的性能和健壮性。在实际开发中,应根据具体的读写比例选择是否使用 CopyOnWriteArrayList,以平衡性能和内存消耗。

上次更新: 2024/11/01, 13:45:14
BlockingQueue
ThreadLocal

← BlockingQueue ThreadLocal→

Copyright © 2023-2024 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式