意见箱
恒创运营部门将仔细参阅您的意见和建议,必要时将通过预留邮箱与您保持联络。感谢您的支持!
意见/建议
提交建议

源码角度了解CopyOnWriteArrayList和CopyOnWriteArraySet

来源:恒创科技 编辑:恒创科技编辑部
2024-01-28 14:17:59
源码角度了解CopyOnWriteArrayList和CopyOnWriteArraySet CopyOnWriteArrayList

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

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

添加元素到尾部的方法

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


源码角度了解CopyOnWriteArrayList和CopyOnWriteArraySet

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();
    }
}
加锁 通过Arrays.copyOf()方法工具类开辟新的数组空间,长度为原长度加一,用来存储传入的元素 新数组的最后一个索引位置放入传入的元素 覆盖原来的数组 解锁 添加元素到指定索引位置的方法
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();
  }
}

代码还是比较好分析的,

计算出需要移动的所谓位置起点 如果不需要移动元素,通过Arrays.copyOf()方法创建新的数据 通过System.arraycopy()方法拷贝原数组elements的从0到index的元素,再拷贝原数组elements的从index+1之后的元素 最后把元素设置新数组的index位置 新数组赋值给原数组 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()方法来保证插入的元素不重复。

上一篇: Java并发编程之美 下一篇: 手机怎么远程登录云服务器?