• CopyOnWriteArrayList源码分析


    目录

    一. 首先我们先来了解一下线程安全的并发集合有哪些?

    二.浅析CopyOnWriteArrayList

    add()方法:

    set()方法:

    remove()方法:

    三.总结


    一. 首先我们先来了解一下线程安全的并发集合有哪些?

    针对ListMapSetDeque等,java.util.concurrent包也提供了对应的并发集合类。归纳如下: 

    接口非线程安全线程安全

    List

    ArrayList

    CopyOnWriteArrayList

    Map

    HashMap

    ConcurrentHashMap

    Set

    HashSet TreeSet

    CopyOnWriteArraySet

    Queue

    ArrayDeque LinkedList

    ArrayBlockingQueue

    LinkedBlockingQueue

    Deque

    ArrayDeque LinkedList

    LinkedBlockingDeque

    这些线程安全的集合,帮助我们很好的处理了多线程并发的情况下的优化,保证了写入与读取的安全。

    二.浅析CopyOnWriteArrayList

       Copy-On-Write简称COW,是一种用于集合的并发访问的优化策略。基本思想是:当我们往一个集合容器中写入元素时(添加、修改、删除),并不会直接在集合容器中写入,而是先将当前集合容器进行Copy,复制出一个新的容器,然后新的容器里写入元素,写入操作完成之后,再将原容器的引用指向新的容器

           CopyOnWriteArrayList常用的方法解析:

    add()方法:

    1. public boolean add(E e) {
    2. final ReentrantLock lock = this.lock;
    3. lock.lock();
    4. try {
    5. //获取原数组
    6. Object[] elements = getArray();
    7. int len = elements.length;
    8. // 复制出新数组
    9. Object[] newElements = Arrays.copyOf(elements, len + 1);
    10. // 把新元素添加到新数组里
    11. newElements[len] = e;
    12. // 把原数组引用指向新数组
    13. setArray(newElements);
    14. return true;
    15. } finally {
    16. lock.unlock();
    17. }
    18. }

    set()方法:

    1. public E set(int index, E element) {
    2. //局部的获取锁对象
    3. final ReentrantLock lock = this.lock;
    4. //加锁
    5. lock.lock();
    6. try {
    7. Object[] elements = getArray();
    8. E oldValue = get(elements, index);
    9. //判断如果要替换成的值与原来的值是否相等
    10. //不相等
    11. if (oldValue != element) {
    12. int len = elements.length;
    13. //把原数组复制到newElements
    14. Object[] newElements = Arrays.copyOf(elements, len);
    15. //进行元素的替换
    16. newElements[index] = element;
    17. setArray(newElements);
    18. } else {
    19. //相等直接存入原数组
    20. setArray(elements);
    21. }
    22. return oldValue;
    23. } finally {
    24. //解锁
    25. lock.unlock();
    26. }
    27. }

    remove()方法:

    1. public E remove(int index) {
    2. //获取锁对象
    3. final ReentrantLock lock = this.lock;
    4. //加锁
    5. lock.lock();
    6. try {
    7. Object[] elements = getArray();
    8. int len = elements.length;
    9. //得到需要通过下标删除的元素值
    10. E oldValue = get(elements, index);
    11. int numMoved = len - index - 1;
    12. if (numMoved == 0)
    13. // 复制原数组中,除最后一个元素以外的所有元素,至新数组
    14. setArray(Arrays.copyOf(elements, len - 1));
    15. else {
    16. // 复制原数组中,除删除元素以外的所有元素,至新数组
    17. Object[] newElements = new Object[len - 1];
    18. System.arraycopy(elements, 0, newElements, 0, index);
    19. System.arraycopy(elements, index + 1, newElements, index,
    20. numMoved);
    21. setArray(newElements);
    22. }
    23. return oldValue;
    24. } finally {
    25. //解锁
    26. lock.unlock();
    27. }
    28. }

    三.总结

            1.这样做的好处:实现对CopyOnWrite集合容器写入操作时的线程安全,但同时并不影响进行并发的读取操作。所以CopyOnWrite容器也是一种读写分离的思想。从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发集合容器,它们是CopyOnWriteArrayListCopyOnWriteArraySet

       2.CopyOnWriteArrayList相当于线程安全的ArrayList,内部存储结构采用Object[]数组,线程安全使用ReentrantLock实现,允许多个线程并发读取,但只能有一个线程写入。

  • 相关阅读:
    golang笔记17--编译调试go源码
    使用PDFBox封装一个简单易用的工具类快速生成pdf文件
    火车头本地文档批量翻译工具
    Python函数详解(三)——函数的参数传递进阶
    靠着数套的Java刷题PDF,成功“混进”腾讯T3
    浅谈分布式系统
    CSS3技巧36:backdrop-filter 背景滤镜
    工作流引擎选择标准与指南
    Linux关于gittee的远端仓库的连接和git三板斧
    Rust权威指南之枚举和模式匹配
  • 原文地址:https://blog.csdn.net/qq_45475528/article/details/126918570