为什么CopyOnWriteArrayList是线程安全的?

为什么ArrayList 是非线程安全的集合类?

arduino 复制代码
public class Demo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                list.add("1");
                System.out.println(list);
            },String.valueOf(i)).start();
        }
    }
}

运行结果会报错,或者打印出来的不对、

原因

ArrayList 是非线程安全的集合类

多个线程同时对 list 进行修改操作(add)和读取操作(toString 内部会遍历)

当一个线程正在遍历时,另一个线程修改了集合结构,就会抛出 ConcurrentModificationException

解决方案

1.使用synchronized关键字

typescript 复制代码
public class Demo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Object lock = new Object();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                synchronized (lock) {
                    list.add("1");
                    System.out.println(list);
                }
            }, String.valueOf(i)).start();
        }
    }
}

2.使用vector

Vector 是 Java 中的一个线程安全的集合类

与 ArrayList 相比,Vector 的方法都是同步的(synchronized)

适用于多线程环境下的使用场景

查看源码可以看到里边就是使用的synchronized关键字。

3.使用Collections.synchronizedList()工具类的方法

typescript 复制代码
public class Demo {
    public static void main(String[] args) {
        List<String> list = Collections.synchronizedList(new ArrayList<>());
        Object lock = new Object();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                synchronized (lock) {
                    list.add("1");
                    System.out.println(list);
                }
            }, String.valueOf(i)).start();
        }
    }

4.使用 CopyOnWriteArrayList(推荐)

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

public class Demo {
    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 10; i++) {
            new Thread(() -> {
                list.add("1");
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
    }
}

CopyOnWriteArrayList

CopyOnWriteArrayList这个是专门设计解决并发环境的线程安全集合。

我们去查看源码:

写操作

你看到这里边也使用了synchronized关键字,使用了lock;这是因为写的时候需要保证数据的一致性。

但是读操作就不需要加锁

CopyOnWriteArrayList 是如何工作的 ?

  • 读操作 (如 get()size())是非常高效的,因为它不涉及锁。每次读操作直接访问底层的数组(它的副本),从而保证了线程安全。
  • 写操作 (如 add()remove()set())需要复制整个数组,修改副本,然后用新的数组替换旧的数组。这种策略避免了读操作被修改中的数组影响,但同时,写操作在多线程中必须进行同步,以防止在修改数组时出现不一致。

为什么同时使用 synchronizedlock

CopyOnWriteArrayList 中使用了synchronizedlock

synchronized lock 的区别

  • synchronized 是 Java 内置的同步机制 ,直接在方法或代码块上加锁,锁的粒度较大,通常适用于简单的同步需求。
  • lock 是通过显式的锁 (如 ReentrantLock)来控制访问,它提供了比 synchronized 更强大的功能,如尝试加锁(tryLock()),中断锁等待等。lock 允许更精细的控制,可以在获取锁时设置超时、获取公平性等。

CopyOnWriteArrayList 中的应用

  • CopyOnWriteArrayList 是线程安全的 集合类,它的底层实现通常会在添加、删除、更新元素时创建一个新的数组,并通过锁来确保写操作的线程安全。
  • locksynchronized 可能用于不同场景中的加锁:
  • 使用 lock
    • CopyOnWriteArrayList 的内部,lock 可能用于更精细的控制,特别是在 写操作 时对底层数组进行复制和修改的过程中。lock 提供了 可中断的锁尝试获取锁公平性控制 等高级功能,这些都可能被用在性能要求较高的场景中。
  • 使用 synchronized
    • synchronized 可能用于 其他部分的同步 ,例如在某些写操作(如 add())的开始和结束之间。synchronized 更适合对临界区(即操作共享资源的代码块)进行加锁。
ini 复制代码
public boolean add(E e) {
    synchronized (lock) {  // 使用 lock 来同步
        Object[] es = getArray();
        int len = es.length;
        es = Arrays.copyOf(es, len + 1);
        es[len] = e;
        setArray(es);
        return true;
    }
}

在这段源码中,synchronized (lock) 用于 同步访问,保证多个线程在执行添加元素的操作时不会发生数据冲突。

总结

优点 :线程安全、高效读操作、不需要显式加锁、适用于读多写少 的场景。
缺点 :写操作性能差、内存开销大、不适合频繁写操作 的场景。

适用场景:适用于读多写少、写操作较少、并发读操作频繁的场景。
CopyOnWriteArrayList 在某些高并发环境中是非常有用的,尤其是希望避免锁竞争、提高读取性能 时。然而,它并不适合所有的场景,特别是写操作较多的情况下,可能需要考虑其他更适合的并发数据结构,如 ConcurrentLinkedQueue ReentrantLock 等。

相关推荐
i***132416 分钟前
Spring BOOT 启动参数
java·spring boot·后端
IT_Octopus20 分钟前
(旧)Spring Securit 实现JWT token认证(多平台登录&部分鉴权)
java·后端·spring
kk哥889925 分钟前
Spring详解
java·后端·spring
S***267528 分钟前
Spring Cloud Gateway 整合Spring Security
java·后端·spring
码事漫谈29 分钟前
C++单元测试框架选型与实战速查手册
后端
OneLIMS35 分钟前
Windows Server 2022 + IIS + ASP.NET Core 完整可上传大文件的 报错的问题
windows·后端·asp.net
码事漫谈44 分钟前
C++ 依赖管理三剑客:vcpkg、Conan、xmake 速查手册
后端
计算机毕设匠心工作室1 小时前
【python大数据毕设实战】青少年抑郁症风险数据分析可视化系统、Hadoop、计算机毕业设计、包括数据爬取、数据分析、数据可视化、机器学习
后端·python
计算机毕设小月哥1 小时前
【Hadoop+Spark+python毕设】智能制造生产效能分析与可视化系统、计算机毕业设计、包括数据爬取、Spark、数据分析、数据可视化、Hadoop
后端·python·mysql
四问四不知1 小时前
Rust语言进阶(结构体)
开发语言·后端·rust