copyOnWriteArrayList<E>源代码

public class CopyOnWriteArrayList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
  // ReentrantLock 可重入锁 ,保证线程安全
  //transient让定义的变量不被序列化
  final transient ReentrantLock lock = new ReentrantLock();

  private transient volatile Object[] array;
  
  //获取数组
  final Object[] getArray() {
        return array;
  }
  
  final void setArray(Object[] a) {
        array = a;
  }

一、无参构造

          作用: 创建一个空数组

public CopyOnWriteArrayList() {
        setArray(new Object[0]);
}

二、获取元素get()

获取元素[读取元素]过程中不加锁,允许多个线程获取

如果获取过程中 ,其他线程向集合中添加新元素,此时读取到的是旧数据

因为添加操作没有对原数组加锁

2.1、根据下标获取元素

    public E get(int index) {
        return get(getArray(), index);
    }

 2.2、根据传入的数组和指定下标,返回该数组中指定下标的元素


    @SuppressWarnings("unchecked")
    private E get(Object[] a, int index) {
        return (E) a[index];
    }

三、set(index,element)

    1.获取锁  【在同一时间只允许一个线程访问】

    2.使用elements数组 来存储  原数组

    3.调用get(element,index)得到指定下标的原来元素值 :oldValue;

    4.判断传入的值与old Value是否一致

     若不一致:进入if 语句块中 :

              先获取原数组长度创建新数组newElements, 再将原数组内容赋值到 新的数组中

              再将传入的新值替换到新数组中指定下标的元素中

              最后将原数组的引用指向新的数组

    若一致:执行else块:

             将原数组的引用指向elements数组

     5.将指定下标位置的旧值返回

     6.释放锁

    public E set(int index, E element) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            E oldValue = get(elements, index);

            if (oldValue != element) {
                int len = elements.length;
                Object[] newElements = Arrays.copyOf(elements, len);
                newElements[index] = element;
                setArray(newElements);
            } else {
                // Not quite a no-op; ensures volatile write semantics
                setArray(elements);
            }
            return oldValue;
        } finally {
            lock.unlock();
        }
    }

四、新元素添加

整体逻辑:

将原来的数组复制Copy 到新数组中 ,将新元素追加至末尾位置,最后替换原数组

会加锁,来保证线程安全

add(E e) 

1.获取原数组并得到其长度

2.将原数组复制到欣数组中

3.将传入的新元素追加到最后

4.原数组引用新数组

5.如果添加成功 返回TRUE;

6.最后释放锁

    
    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();
        }
    }

add(index ,e)  方法重载 

1.加锁 获取原数组【以及长度】

2.判断传入的index【位置】是否合法,如果非法【大于长度或或者小于0】,则抛出异常

3.计算需要移动的元素个数numMoved 【len - index】

    若 = 0 ,表示新元素的下标 在数组的最后位置,

        此时:使用Arrays类复制原数组至新数组,长度加1

   否则 :

      创建新数组,其长度比原数组多1

      将0到index位置的元素复制到新数组的指定位置

 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();
        }
    }

remove(index) 

功能:删除指定下标元素

整体逻辑:根据指定下标,从原数组中,Copy复制其它元素至新数组中,最后替换原数组

public E remove(int index) {
        final ReentrantLock lock = this.lock;
        lock.lock();//加锁
        try {
            Object[] elements = getArray();
            int len = elements.length;
            E oldValue = get(elements, index);
            int numMoved = len - index - 1;
            if (numMoved == 0)
                setArray(Arrays.copyOf(elements, len - 1));
            else {
                Object[] newElements = new Object[len - 1];
                System.arraycopy(elements, 0, newElements, 0, index);
                System.arraycopy(elements, index + 1, newElements, index,
                                 numMoved);
                setArray(newElements);
            }
            return oldValue;//返回删除前该位置的元素值
        } finally {
            lock.unlock();
        }
    }

removeRange(fromIndex,toIndex)

功能:按照指定范围删除元素

1.加锁 获取原数组【以及长度】

2.判断传入删除位置【index】是否合法,如果非法【大于长度或或者小于0】,则抛出异常

3. 不满足则抛出异常

4.计算新数组的长度 = len -(toIndex-fromIndex)

5. 计算需要移动的元素个数numMoved 【len -toindex】

      5.1、若 numMoved= 0 ,表示需要移动的元素个数为0【删除范围在元素组最后】

               使用Arrays类复制原数组至新数组,长度加1

      5.2、 否则 :【元素组分为两部分--->将这两部分的元素复制至新数组中】

           创建新数组,其长度为newlen,

         前段: 将原数组从0位置开始后fromIndex个元素复制至新数组【从0开始】    

         后端:  将原数组从toIndex位置开始后numMoved个元素复制至新数组【从 fromIndex开始】

6.改变原数组引用【将指向新数组】

7.最后 关闭锁

  void removeRange(int fromIndex, int toIndex) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;

            if (fromIndex < 0 || toIndex > len || toIndex < fromIndex)
                throw new IndexOutOfBoundsException();
            int newlen = len - (toIndex - fromIndex);
            int numMoved = len - toIndex;
            if (numMoved == 0)
                setArray(Arrays.copyOf(elements, newlen));
            else {
                Object[] newElements = new Object[newlen];
                System.arraycopy(elements, 0, newElements, 0, fromIndex);
                System.arraycopy(elements, toIndex, newElements,
                                 fromIndex, numMoved);
                setArray(newElements);
            }
        } finally {
            lock.unlock();
        }
    }

removeAll(Collection<?> c) 

功能:传入一个集合,删除元素组中该集合中的所有元素【去交集】

1.判断传入集合c是否为空指针,满足抛出异常

   若传入集合c为空,则返回false ,

2.定义并加锁

3.获取元素组及长度

4.判断长度是否为0

  若不为0,定义临时数组temp,长度为数组长度

  开始遍历数组,获取每一个元素

   判断集合中是否包含该元素  :若不包含,判断下一个,并将该元素以此存入temp临时数组中 

5.如果临时数组的长度newlen不等于原数组长度len

    将temp数组中的newlen个元素复制到新数组中,再将引用传给原数组

6.返回

    public boolean removeAll(Collection<?> c) {
        if (c == null) throw new NullPointerException();
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            if (len != 0) {
                // temp array holds those elements we know we want to keep
                int newlen = 0;
                Object[] temp = new Object[len];
                for (int i = 0; i < len; ++i) {
                    Object element = elements[i];
                    if (!c.contains(element))
                        temp[newlen++] = element;
                }
                if (newlen != len) {
                    setArray(Arrays.copyOf(temp, newlen));
                    return true;
                }
            }
            return false;
        } finally {
            lock.unlock();
        }
    }

clear()

    public void clear() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            setArray(new Object[0]);
        } finally {
            lock.unlock();
        }
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值