Java基础 -04 List之CopyOnWriteArrayList

这篇具有很好参考价值的文章主要介绍了Java基础 -04 List之CopyOnWriteArrayList。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

java集合有蛮多的类型,今天我们以CopyOnWriteArrayList和Vector进行相关介绍。

CopyOnWriteArrayList

CopyOnWriteArrayList是Java集合框架中的一个线程安全的List实现类。它通过在修改操作时创建一个新的副本来实现线程安全性,因此称为"写时复制"。

Copy-On-Write简称COW,是一种用于程序设计中的优化策略。CopyOnWrite容器即写时复制的容器。通俗的理解是当往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

CopyOnWrite并发容器用于读多写少的并发场景。

复制用法导致内存占用可能过高。

保证数据最终一致性,无法保证实时一致性。

Java基础 -04 List之CopyOnWriteArrayList,java,java,list,开发语言
Java基础 -04 List之CopyOnWriteArrayList,java,java,list,开发语言

特点

  • 线程安全:CopyOnWriteArrayList是线程安全的,多个线程可以同时读取列表中的元素,而不需要额外的同步措施。这使得它非常适合在多线程环境下进行读取操作。

  • 写时复制:当有线程对CopyOnWriteArrayList进行修改操作(如添加、删除元素)时,它会创建一个新的副本,并在副本上进行修改操作。这样,其他线程仍然可以在原始列表上进行读取操作,不会受到修改操作的影响。一旦修改完成,新的副本会替换原始列表,以确保修改的一致性。

  • 高效的读取操作:由于读取操作不需要进行同步,CopyOnWriteArrayList在读取操作上具有很高的性能。这使得它非常适合在读多写少的场景中使用。

  • 低效的写入操作:由于每次写入操作都需要创建一个新的副本,CopyOnWriteArrayList在写入操作上的性能相对较低。因此,如果应用程序中有大量的写入操作,可能会影响性能。

  • 迭代器的弱一致性:CopyOnWriteArrayList的迭代器提供了弱一致性的保证。即,迭代器在创建时会获取一个快照,并在迭代过程中遍历该快照。这意味着迭代器不会反映出在迭代过程中对列表所做的修改。

CopyOnWriteArrayList适用于读多写少的场景,特别是在需要保证线程安全性的情况下。它常用于事件监听器列表、缓存等场景,其中读取操作远远超过写入操作。

    public static void main(String[] args) {
        CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();

        // 添加元素
        list.add("Apple");
        list.add("Banana");
        list.add("Orange");

        // 遍历元素
        for (String element : list) {
            System.out.println(element);
        }

        // 修改元素
        list.set(1, "Grape");

        // 删除元素
        list.remove("Apple");

        // 遍历元素
        for (String element : list) {
            System.out.println(element);
        }
    }

CopyOnWriteArrayList是如何保证安全的

CopyOnWriteArrayList通过"写时复制"(Copy-On-Write)机制来保证线程安全性。具体来说,当有线程对CopyOnWriteArrayList进行修改操作时,它会创建一个新的副本,并在副本上进行修改操作。这样,其他线程仍然可以在原始列表上进行读取操作,不会受到修改操作的影响。一旦修改完成,新的副本会替换原始列表,以确保修改的一致性。

这种机制的实现步骤如下:

  • 当有线程要对CopyOnWriteArrayList进行修改操作时,它首先会创建一个当前列表的副本。

  • 在副本上进行修改操作,例如添加、删除元素等。

  • 修改完成后,将新的副本替换原始列表,使得其他线程可以看到最新的修改。

通过这种方式,CopyOnWriteArrayList实现了线程安全性,因为每个线程都在自己的副本上进行修改操作,不会影响其他线程的读取操作。这样就避免了传统的同步机制(如锁)带来的竞争和阻塞。

需要注意的是,由于每次修改操作都会创建一个新的副本,CopyOnWriteArrayList在写入操作上的性能相对较低。因此,它更适合于读多写少的场景,特别是在需要保证线程安全性的情况下。

代码层次分析

我们可以从代码层面进行相关分析:

  • 写操作的实现:CopyOnWriteArrayList的写操作(如添加、删除元素)是通过创建一个新的副本来实现的。在添加元素时,会创建一个新的数组,并将原始数组中的元素复制到新数组中,然后在新数组中添加新元素。删除元素时,也是创建一个新的数组,并将原始数组中的元素复制到新数组中,但是不包括要删除的元素。最后,将新数组替换原始数组。

  • 读操作的实现:CopyOnWriteArrayList的读操作是在原始数组上进行的,不需要额外的同步措施。这是因为在写操作期间,读操作仍然可以访问原始数组,不会受到写操作的影响。这样可以保证读操作的线程安全性。

  • 使用volatile关键字:CopyOnWriteArrayList内部使用了volatile关键字来保证多线程之间的可见性。当一个线程修改了列表时,它会将新的副本赋值给volatile修饰的数组引用,以便其他线程可以看到最新的修改。

  • 迭代器的一致性:CopyOnWriteArrayList的迭代器提供了弱一致性的保证。即,迭代器在创建时会获取一个快照,并在迭代过程中遍历该快照。这意味着迭代器不会反映出在迭代过程中对列表所做的修改。

CopyOnWriteArrayList实现了线程安全性。每个线程在修改操作时都会在自己的副本上进行操作,不会影响其他线程的读取操作。这样就避免了传统的同步机制(如锁)带来的竞争和阻塞,提供了高效的线程安全的List实现。

案例说明

假设我们有一个任务列表,多个线程同时对任务列表进行读取和修改操作。我们使用CopyOnWriteArrayList来存储任务列表,并保证线程安全。


public class TaskList {
    private CopyOnWriteArrayList<String> tasks = new CopyOnWriteArrayList<>();

    public void addTask(String task) {
        tasks.add(task);
    }

    public void removeTask(String task) {
        tasks.remove(task);
    }

    public void printTasks() {
        for (String task : tasks) {
            System.out.println(task);
        }
    }
}

我们创建多个线程来对任务列表进行读取和修改操作:

public class Main {
    public static void main(String[] args) {
        TaskList taskList = new TaskList();

        // 创建多个线程进行读取和修改操作
        Thread readerThread1 = new Thread(() -> {
            taskList.printTasks();
        });

        Thread readerThread2 = new Thread(() -> {
            taskList.printTasks();
        });

        Thread writerThread1 = new Thread(() -> {
            taskList.addTask("Task 1");
        });

        Thread writerThread2 = new Thread(() -> {
            taskList.removeTask("Task 1");
        });

        // 启动线程
        readerThread1.start();
        readerThread2.start();
        writerThread1.start();
        writerThread2.start();
    }
}

我们创建了两个读取线程(readerThread1和readerThread2)和两个修改线程(writerThread1和writerThread2)。读取线程通过调用printTasks方法来打印任务列表,修改线程通过调用addTask和removeTask方法来添加和删除任务。

由于CopyOnWriteArrayList的线程安全性,多个线程可以同时读取和修改任务列表,而不需要额外的同步措施。读取线程可以在修改线程进行操作的同时访问任务列表,并且不会受到修改操作的影响。

我们可以看到CopyOnWriteArrayList的线程安全性。每个线程在修改操作时都会在自己的副本上进行操作,不会影响其他线程的读取操作。这样就实现了多线程环境下的安全访问和修改任务列表。文章来源地址https://www.toymoban.com/news/detail-799636.html

到了这里,关于Java基础 -04 List之CopyOnWriteArrayList的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Java基础_集合类_List

    类图: (1)AbstractCollection Collection接口的骨架式实现类,最小化实现Collection接口的代价。 (2)AbstractList List接口的骨架式实现类,最小化实现List接口的代价。**“随机访问”**数据存储。 提供了iterator()、listIterator()方法的实现。 重要属性 : protected transient int modCount;【 修改

    2024年04月28日
    浏览(45)
  • java基础 - 03 List之AbstractSequentialList、LinkedList

    上一篇我们围绕了ArrayList以及List进行简单介绍,本篇我们将围绕AbstractSequentialList、LinkedList进行。 AbstractSequentialList 是Java集合框架中的一个抽象类,它实现了List接口,并且是 针对顺序访问的列表数据结构的基类 。它提供了一些通用的方法实现,以简化具体实现类的开发。

    2024年01月16日
    浏览(38)
  • java基础 -02java集合之 List,AbstractList,ArrayList介绍

    在正式List之前,我们先了解我们补充上篇Collection接口的拓展实现,也就是说当我我们需要实现一个不可修改的Collection的时候,我们只需要拓展某个类,也就是AbstractCollection这个类,他是Collection接口的骨干实现,并以最大限度的实现了减少此接口所需要的工作; 如上两图进行

    2024年01月20日
    浏览(42)
  • Java基础六 - Collection集合List、Set、Queue,Map

    1. List - ArrayList、LinkedList、Vector ArrayList         2. LinkedList         3. Vector         4. 常见使用方法 2. Set - HashSet、LinkedHashSet、TreeSet 1. HashSet 2. LinkedHashSet 3. TreeSet 4. 常用方法 3. Map - HashMap、TreeMap、LinkedHashMap、Hashtable 1. HashMap 2. LinkedHashMap 3. TreeMap 4. Hashtable 5.

    2024年02月14日
    浏览(49)
  • Java基础面试题04(网络编程)

    什么是网络编程?它的作用是什么? 网络编程是一种用于在计算机网络中进行数据交换和通信的编程技术。它涉及到使用网络协议和相关工具来实现程序之间的通信。网络编程的目标是允许不同设备或应用程序之间进行数据传输、共享资源和进行远程控制。 网络编程的作用

    2024年02月15日
    浏览(44)
  • 【Java基础】Java8 使用 stream().filter()过滤List对象(查找符合条件的对象集合)

    本篇主要说明在Java8及以上版本中,使用stream().filter()来过滤List对象,查找符合条件的集合。 集合对象以学生类(Student)为例,有学生的基本信息,包括:姓名,性别,年龄,身高,生日几项。 我的学生类代码如下: 下面来添加一些测试用的数据,代码如下: 添加过滤条件

    2024年02月12日
    浏览(68)
  • java自动化-03-04java基础之数据类型举例

    1、需要特殊注意的数据类型举例 1)定义float类型,赋值时需要再小数后面带f 2)定义double类型,赋值时直接输入小数就可以 3)另外需要注意,float类型的精度问题,会有自动保存小数点后几位的问题,如下图 4)boolean类型的值只有true和false 5)char类型的变量进行赋值时需要

    2024年04月11日
    浏览(41)
  • CopyOnWriteArrayList的应用与原理

    JUC篇:volatile可见性的实现原理 JUC篇:synchronized的应用和实现原理 JUC篇:用Java实现一个简单的线程池 JUC篇:java中的线程池 JUC篇:ThreadLocal的应用与原理 JUC篇:Java中的并发工具类 并发包中的并发List只有CopyOnWriteArrayList。 CopyOnWriteArrayList是一个线程安全的ArrayList ,对其进行

    2023年04月16日
    浏览(30)
  • JUC篇:CopyOnWriteArrayList的应用与原理

    JUC篇:volatile可见性的实现原理 JUC篇:synchronized的应用和实现原理 JUC篇:用Java实现一个简单的线程池 JUC篇:java中的线程池 JUC篇:ThreadLocal的应用与原理 JUC篇:Java中的并发工具类 并发包中的并发List只有CopyOnWriteArrayList。 CopyOnWriteArrayList是一个线程安全的ArrayList ,对其进行

    2023年04月08日
    浏览(25)
  • mysql数据库面试题基础知识,Hadoop之MapReduce04,腾讯java面试流程

    该方法的执行过程比较复杂,我们慢慢来分析,首先来看下简化的时序图 3.1waitForCompletion public boolean waitForCompletion(boolean verbose ) throws IOException, InterruptedException, ClassNotFoundException { // 判断任务的状态,如果是DEFINE就提交 if (state == JobState.DEFINE) { submit(); } if (verbose) { // 监听并且

    2024年04月14日
    浏览(62)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包