CopyOnWriteArrayList 原理,优缺点

CopyOnWriteArrayList是Java并发包中提供的一种线程安全的ArrayList,其原理、优缺点可以归纳如下:

原理

CopyOnWriteArrayList的核心思想是"写时复制"(Copy-On-Write, COW),即在修改操作(添加、删除元素等)时,不是直接修改当前容器,而是先复制一份当前容器的副本,然后在副本上进行修改操作,最后再将原容器的引用指向修改后的新容器。这种机制保证了读操作不会受到写操作的阻塞,因此读操作是完全不用加锁的,性能较高。

优点

  1. 并发读性能高:由于读操作不需要加锁,且不会受到写操作的阻塞,因此在读操作远多于写操作的并发场景中,CopyOnWriteArrayList的性能表现非常出色。
  2. 线程安全:CopyOnWriteArrayList内部实现了线程安全的机制,无需外部同步,简化了并发编程的复杂性。
  3. 迭代器安全:CopyOnWriteArrayList提供了一个弱一致性的迭代器(Weakly Consistent Iterator),即在迭代过程中,即使列表发生了修改,迭代器仍然可以安全地进行,不会抛出ConcurrentModificationException异常。

缺点

  1. 内存开销大:由于每次写操作都会创建底层数组的一个副本,因此CopyOnWriteArrayList的内存开销相对较大。特别是在列表包含大量元素时,每次写操作都需要复制整个数组,这不仅会增加内存消耗,还可能导致Garbage Collection频繁发生,影响系统性能。
  2. 写操作性能低:由于每次写操作都需要复制整个底层数组,这使得写操作的时间复杂度是O(n),其中n是数组的大小。因此,在需要频繁写操作的场景下,CopyOnWriteArrayList的性能会非常低下。
  3. 数据实时性差:CopyOnWriteArrayList在每次写操作时都要复制整个数组,因此不适合用于需要实时读取最新数据的场景。在读取过程中,如果另一个线程完成了写操作,但由于读操作是在旧数组上进行的,读取线程依然会获取到写操作之前的数据。

使用场景

CopyOnWriteArrayList最适合的场景是读多写少的场景,如配置管理、事件监听器列表 等。在这些场景中,读操作非常频繁,而写操作相对较少。由于读操作无锁且非常高效,因此CopyOnWriteArrayList能够提供优异的性能。

实例

java 复制代码
import java.util.concurrent.CopyOnWriteArrayList;  
  
public class CopyOnWriteArrayListExample {  
    public static void main(String[] args) {  
        // 创建一个CopyOnWriteArrayList对象  
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();  
  
        // 添加元素到列表中  
        list.add("Alice");  
        list.add("Bob");  
        list.add("Charlie");  
  
        // 遍历并打印列表中的元素  
        System.out.println("Initial List:");  
        for (String element : list) {  
            System.out.println(element);  
        }  
  
        // 创建并启动多个线程,一个用于添加元素,一个用于删除元素  
        Thread thread1 = new Thread(new AddElementTask(list));  
        Thread thread2 = new Thread(new RemoveElementTask(list));  
  
        thread1.start();  
        thread2.start();  
  
        // 等待线程执行完毕  
        try {  
            thread1.join();  
            thread2.join();  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
  
        // 遍历并打印最终的列表内容  
        System.out.println("Final List:");  
        for (String element : list) {  
            System.out.println(element);  
        }  
    }  
  
    // 添加元素的线程任务  
    static class AddElementTask implements Runnable {  
        private CopyOnWriteArrayList<String> list;  
  
        public AddElementTask(CopyOnWriteArrayList<String> list) {  
            this.list = list;  
        }  
  
        @Override  
        public void run() {  
            for (int i = 1; i <= 5; i++) {  
                list.add("Element " + i);  
                System.out.println("Added Element " + i);  
                try {  
                    Thread.sleep(100); // 模拟一些延迟  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
    }  
  
    // 删除元素的线程任务  
    static class RemoveElementTask implements Runnable {  
        private CopyOnWriteArrayList<String> list;  
  
        public RemoveElementTask(CopyOnWriteArrayList<String> list) {  
            this.list = list;  
        }  
  
        @Override  
        public void run() {  
            for (int i = 1; i <= 3; i++) {  
                if (list.size() > 0) {  
                    String removedElement = list.remove(0);  
                    System.out.println("Removed " + removedElement);  
                }  
                try {  
                    Thread.sleep(200); // 模拟一些延迟  
                } catch (InterruptedException e) {  
                    e.printStackTrace();  
                }  
            }  
        }  
    }  
}

运行结果

bash 复制代码
Initial List:
Alice
Bob
Charlie
Removed Alice
Added Element 1
Added Element 2
Removed Bob
Added Element 3
Added Element 4
Removed Charlie
Added Element 5
Final List:
Element 1
Element 2
Element 3
Element 4
Element 5

与List性能对比(add)

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

public class CopyOnWriteArrayListCompareListExample {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> copList = new CopyOnWriteArrayList<>();
        long begin = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            copList.add(String.valueOf(i));
        }
        long end = System.currentTimeMillis();
        System.out.println("CopyOnWriteArrayList:"+(end - begin));


        List<String> list = new CopyOnWriteArrayList<>();
        long beginList = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            list.add(String.valueOf(i));
        }
        long endList = System.currentTimeMillis();
        System.out.println("List:"+(endList - beginList));
    }
}

运行结果

bash 复制代码
CopyOnWriteArrayList:2128
List:1936
相关推荐
学传打活14 小时前
【边打字.边学昆仑正义文化】_进阶篇5 宇宙星系的运转(续3)
微信公众平台·1024程序员节·汉字·昆仑正义文化
学传打活6 天前
【边打字.边学昆仑正义文化】_进阶篇5 宇宙星系的运转(续1)
微信公众平台·1024程序员节·汉字·昆仑正义文化
fangzhanpeng16814 天前
快速掌握C#语言基础知识点(1.基础数据类型)
开发语言·c#·1024程序员节
无己心16 天前
面向多平台 AI 搜索引擎的适配层架构设计
前端·人工智能·搜索引擎·ai·1024程序员节
u01030552722 天前
AI驱动的安卓UI自动生成功能实现
人工智能·1024程序员节
u01030552722 天前
长株潭智能体赋能腾讯元器链接共享
1024程序员节
云贝贝贝24 天前
OceanBase认证体系介绍与备考指南
运维·服务器·oceanbase·1024程序员节
u01030552724 天前
Java图像处理实战指南
人工智能·1024程序员节
u01030552724 天前
Java AWT鼠标事件全解析
人工智能·1024程序员节
u0103055271 个月前
Java实用类应用精讲
人工智能·1024程序员节