CopyOnWriteArrayList

  • CopyOnWriteArrayList 线程安全
    • 使用分析
      • 优点
        • 性能高:读取没有锁,更改才有锁
        • 读写隔离高:更改时不影响正常读取
      • 缺点
        • 性能问题:不适合写操作多场景,导致复制次数多,性能低
        • 内存问题:不适合数据量大的场景,导致每次复制时占用内存多
        • 数据弱一致性: 不支持快速失败机制,在修改操作开始和结束之间读取的都是老数据
      • 适用场景:写操作不多,数据量不大,内存资源充足的情况
    • 设计分析
      • 设计目标
        • List可以同时达到多线程的安全和性能的高效
      • 设计思路
        • 要解决的问题
          • 多线程安全问题和性能高效问题
        • 解决问题的思路
          • 读取操作不加锁,修改操作加锁但不能影响读取操作。
        • 解决问题的方案
          • Coyp On Write 方案解决修改时的多线程安全问题,并保证修改时不影响读取操作
      • 实现原理
        • 读取没有锁
        • 添加和删除时使用ReentrantLock锁
        • 每次添加和删除时使用Arrays.copyOf()生成只多一个或者少一个长度的数组,没有倍数扩容和缩容
        • 更改操作完成后,将老数组指针指向新数组
        • 基于Object[]实现
    • 源码分析
      • 继承关系
        • public class CopyOnWriteArrayList<E>
          extends Object
          implements List<E>, RandomAccess, Cloneable, Serializable

      • add方法
        • public boolean add(E e) {
              final ReentrantLock lock = this.lock;
              // 加锁
              lock.lock();
              try {
                  // 获取原来的数组
                  Object[] elements = getArray();
                  // 原来数组的长度
                  int len = elements.length;
                  // 创建一个长度+1的新数组,并将原来数组的元素复制给新数组
                  Object[] newElements = Arrays.copyOf(elements, len + 1);
                  // 元素放在新数组末尾
                  newElements[len] = e;
                  // array指向新数组
                  setArray(newElements);
                  return true;
              } finally {
                  // 解锁
                  lock.unlock();
              }
          }

      • 删除方法
        • public E remove(int index) {
              // 获取可重入锁
              final ReentrantLock lock = this.lock;
              // 加锁
              lock.lock();
              try {
                   //获取当前array数组
                  Object[] elements = getArray();
                  // 获取当前array长度
                  int len = elements.length;
                  //获取指定索引的元素(旧值)
                  E oldValue = get(elements, index);
                  int numMoved = len - index - 1;
                  // 判断删除的是否是最后一个元素
                  if (numMoved == 0)
                       // 如果删除的是最后一个元素,直接复制该元素前的所有元素到新的数组
                      setArray(Arrays.copyOf(elements, len - 1));
                  else {
                      // 分段复制,将index前的元素和index+1后的元素复制到新数组
                      // 新数组长度为旧数组长度-1
                      Object[] newElements = new Object[len - 1];
                      System.arraycopy(elements, 0, newElements, 0, index);
                      System.arraycopy(elements, index + 1, newElements, index,
                                       numMoved);
                      //将新数组赋值给array引用
                      setArray(newElements);
                  }
                  return oldValue;
              } finally {
                   // 解锁
                  lock.unlock();
              }
          }
    • https://javaguide.cn/java/collection/copyonwritearraylist-source-code.html
posted @ 2025-04-21 10:22  一点点征服  阅读(24)  评论(0)    收藏  举报