源码角度了解CopyOnWriteArrayList和CopyOnWriteArraySet

举报
周杰伦本人 发表于 2022/09/30 00:06:44 2022/09/30
【摘要】 源码角度了解CopyOnWriteArrayList和CopyOnWriteArraySet CopyOnWriteArrayList 添加元素到尾部的方法 添加元素到指定索引位置的方法 CopyOnWriteArraySet 总结 源码角度了解CopyOnWriteArrayList和CopyOnWriteArraySet CopyOnWriteArrayListCopyOnWriteA...

源码角度了解CopyOnWriteArrayList和CopyOnWriteArraySet

CopyOnWriteArrayList

CopyOnWriteArrayList在读的时候不加锁,写的时候加锁,它的原理是在写的时候复制一份源数据,然后修改,再写回到原数组中,它的成员变量array用来保存元素,被volatile修饰来

由于它的get()请求很简单,没有加锁,这里就不分析了,我们分析它的写操作

添加元素到尾部的方法

add()方法是将元素添加到列表末尾

public boolean add(E e) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] elements = getArray();
        int len = elements.length;
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        newElements[len] = e;
        setArray(newElements);
        return true;
    } finally {
        lock.unlock();
    }
}
  1. 第一步进行加锁
  2. 通过Arrays.copyOf()方法工具类开辟新的数组空间,长度为原长度加一,用来存储传入的元素
  3. 新数组的最后一个索引位置放入传入的元素
  4. 覆盖原来的数组
  5. 最后一步进行解锁

添加元素到指定索引位置的方法

public void add(int index, E element) {
  final ReentrantLock lock = this.lock;
  lock.lock();
  try {
      Object[] elements = getArray();
      int len = elements.length;
      if (index > len || index < 0)
          throw new IndexOutOfBoundsException("Index: "+index+
                                              ", Size: "+len);
      Object[] newElements;
      int numMoved = len - index;
      if (numMoved == 0)
          newElements = Arrays.copyOf(elements, len + 1);
      else {
          newElements = new Object[len + 1];
          System.arraycopy(elements, 0, newElements, 0, index);
          System.arraycopy(elements, index, newElements, index + 1,
                           numMoved);
      }
      newElements[index] = element;
      setArray(newElements);
  } finally {
      lock.unlock();
  }
}

代码还是比较好分析的,

  1. 计算出需要移动的所谓位置起点
  2. 如果不需要移动元素,通过Arrays.copyOf()方法创建新的数据
  3. 通过System.arraycopy()方法拷贝原数组elements的从0到index的元素,再拷贝原数组elements的从index+1之后的元素
  4. 最后把元素设置新数组的index位置
  5. 新数组赋值给原数组

CopyOnWriteArraySet

CopyOnWriteArraySet保证元素不重复,它的成员变量只有一个CopyOnWriteArrayList<E> al,所有的操作都是基于CopyOnWriteArrayList的,我们看一下它的add()方法

public boolean add(E e) {
    return al.addIfAbsent(e);
}

直接调用了CopyOnWriteArrayList的addIfAbsent(),这个方法就是元素不存在的话添加元素到末尾,存在就不再添加了。

总结

这篇文章我们讲了CopyOnWriteArrayList和CopyOnWriteArraySet,CopyOnWriteArrayList读的时候不加锁,写的时候加锁,并开辟新的空间数组,在插入位置的前后部分数组元素复制到新数组中,插入位置添加新元素,新的数组再赋值给原数组,最后解锁。CopyOnWriteArraySet保证元素不重复,它只有一个成员变量是CopyOnWriteArrayList,它的方法都是基于CopyOnWriteArrayList完成的,add()方法中直接调用CopyOnWriteArrayList的addIfAbsent()方法来保证插入的元素不重复。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。