Java集合类框架源码分析 之 CopyOnWriteArrayList源码解析 【5】

类简介,主要的特性为:

读方法不加锁,修改方法加锁,避免所线程场景所引起的问题,加锁使用 final transient ReentrantLock lock = new ReentrantLock(); 来实现锁的获取和释放

/**
 * 该类是ArrayList的一个变体,是线程安全的,所有变更操作(add/set..)都被设计为对底层数组的全新的一个复制操作。
 * 怎么理解呢:就是所每次经过add/set等改变结构的操作后,底层数组都是重新创建的,而不是和arraylist一样,在数组的基础上进行增删。
 * 稍后我们可以通过add(),对这个结论进行验证
 * A thread-safe variant of {@link java.util.ArrayList} in which all mutative
 * operations ({@code add}, {@code set}, and so on) are implemented by
 * making a fresh copy of the underlying array.
 *
 * 但是,当遍历操作的数量远远超过突变时,可能比替代方法更有效,并且当您不能或不想同步遍历,但又需要防止并发线程之间的干扰时,会很有用。
 * 快照模式的迭代器方法使用了一个在迭代器被创建时,对数组状态的引用。数组在整个迭代器的生命周期内不能被改变。
 * 因此不存在冲突,并且迭代器保证不会抛出 ConcurrentModificationException异常。当迭代器创建后,迭代器不会反映增加/删除或者list的改变。
 * 迭代器本身不支持元素的add/remove/set等改变操作,这些方法会抛出 UnsupportedOperationException异常。
 * <p>This is ordinarily too costly, but may be <em>more</em> efficient
 * than alternatives when traversal operations vastly outnumber
 * mutations, and is useful when you cannot or don't want to
 * synchronize traversals, yet need to preclude interference among
 * concurrent threads.  The "snapshot" style iterator method uses a
 * reference to the state of the array at the point that the iterator
 * was created. This array never changes during the lifetime of the
 * iterator, so interference is impossible and the iterator is
 * guaranteed not to throw {@code ConcurrentModificationException}.
 * The iterator will not reflect additions, removals, or changes to
 * the list since the iterator was created.  Element-changing
 * operations on iterators themselves ({@code remove}, {@code set}, and
 * {@code add}) are not supported. These methods throw
 * {@code UnsupportedOperationException}.
 *
 * <p>All elements are permitted, including {@code null}.
 *
 * 内存一致性影响:和其他并发集合一样,一个线程先放入元素,另外一个线程删除了整个元素。造成内存的不一致。
 * <p>Memory consistency effects: As with other concurrent
 * collections, actions in a thread prior to placing an object into a
 * {@code CopyOnWriteArrayList}
 * <a href="package-summary.html#MemoryVisibility"><i>happen-before</i></a>
 * actions subsequent to the access or removal of that element from
 * the {@code CopyOnWriteArrayList} in another thread.
 *
 */

具体方法分析:

add()方法:实现的效果和之前文章中分析的ArrayList源码分析t源码分析,LinkedList源码分析都是一样的,向当前列表中添加元素,但是实现方法不同,通过 final transient ReentrantLock lock = new ReentrantLock(); 来获取和释放锁对象。

比较核心的一行代码为:

            Object[] newElements = Arrays.copyOf(elements, len + 1); // 复制了一个新的数组

复制了新的数组,并将原来数组中的元素,复制到新数组中的合适的位置,可能是末尾,可能是中间,如果是中间,会发生原有数组中元素索引位置的移动。 

    /**
     * 向list末尾追加元素
     * Appends the specified element to the end of this list.
     *
     */
    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)
     * Inserts the specified element at the specified position in this
     * list. Shifts the element currently at that position (if any) and
     * any subsequent elements to the right (adds one to their indices).
     *
     * 超过数组边界,抛出 IndexOutOfBoundsException 异常。
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    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); // 当插入到list头时,直接扩充一个数组位置
            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();
        }
    }

添加元素时,进行判断,当前列表中不存在时,才进行添加:addIfAbsent():

    /**
     * 将指定list中,没包含在当前list中的元素,添加到当前list的末尾,添加元素的顺序,以指定list的iterator返回的顺序为准。
     * Appends all of the elements in the specified collection that
     * are not already contained in this list, to the end of
     * this list, in the order that they are returned by the
     * specified collection's iterator.
     *
     * @param c collection containing elements to be added to this list
     * @return the number of elements added
     * @throws NullPointerException if the specified collection is null
     * @see #addIfAbsent(Object)
     */
    public int addAllAbsent(Collection<? extends E> c) {
        Object[] cs = c.toArray();
        if (cs.length == 0)
            return 0;
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            int added = 0;
            // uniquify and compact elements in cs
            for (int i = 0; i < cs.length; ++i) {
                Object e = cs[i];
                if (indexOf(e, elements, 0, len) < 0 &&
                    indexOf(e, cs, 0, added) < 0)
                    cs[added++] = e;
            }
            if (added > 0) {
                Object[] newElements = Arrays.copyOf(elements, len + added);
                System.arraycopy(cs, 0, newElements, len, added);
                setArray(newElements);
            }
            return added;
        } finally {
            lock.unlock();
        }
    }

将指定列表中的元素,全部添加到当前列表中:

    /**
     * 将指定元素中所有的元素,按照指定列表的iterator返回的顺序,添加到当前list中
     * Appends all of the elements in the specified collection to the end
     * of this list, in the order that they are returned by the specified
     * collection's iterator.
     *
     * @param c collection containing elements to be added to this list
     * @return {@code true} if this list changed as a result of the call
     * @throws NullPointerException if the specified collection is null
     * @see #add(Object)
     */
    public boolean addAll(Collection<? extends E> c) {
        Object[] cs = (c.getClass() == CopyOnWriteArrayList.class) ?
            ((CopyOnWriteArrayList<?>)c).getArray() : c.toArray();
        if (cs.length == 0)
            return false;
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            if (len == 0 && cs.getClass() == Object[].class)
                setArray(cs);
            else {
                Object[] newElements = Arrays.copyOf(elements, len + cs.length);
                System.arraycopy(cs, 0, newElements, len, cs.length);
                setArray(newElements);
            }
            return true;
        } finally {
            lock.unlock();
        }
    }

删除元素:remove(Object o ),删除在列表中出现的元素o,如果存在多个,则删除第一个(索引数最小的元素)。

    /**
     * 删除list中出现的第一个指定的o。
     * Removes the first occurrence of the specified element from this list,
     * if it is present.  If this list does not contain the element, it is
     * unchanged.  More formally, removes the element with the lowest index
     * {@code i} such that
     * <tt>(o==null&nbsp;?&nbsp;get(i)==null&nbsp;:&nbsp;o.equals(get(i)))</tt>
     * (if such an element exists).  
     */
    public boolean remove(Object o) {
        Object[] snapshot = getArray();
        int index = indexOf(o, snapshot, 0, snapshot.length);
        return (index < 0) ? false : remove(o, snapshot, index);
    }

    /**
     * A version of remove(Object) using the strong hint that given
     * recent snapshot contains o at the given index.
     */
    private boolean remove(Object o, Object[] snapshot, int index) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] current = getArray();
            int len = current.length;
            if (snapshot != current) findIndex: { // 重新根据快照和当前数据进行比对,看过程中是否出现了对array的修改
                int prefix = Math.min(index, len);
                for (int i = 0; i < prefix; i++) {
                    if (current[i] != snapshot[i] && eq(o, current[i])) { // 判断是否出现修改的逻辑
                        index = i;
                        break findIndex;
                    }
                }
                if (index >= len)
                    return false;
                if (current[index] == o)
                    break findIndex;
                index = indexOf(o, current, index, len);
                if (index < 0)
                    return false;
            }
            Object[] newElements = new Object[len - 1]; // 创建新的数组
            System.arraycopy(current, 0, newElements, 0, index); // 对原来的数组进行复制
            System.arraycopy(current, index + 1,
                             newElements, index,
                             len - index - 1);
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

删除指定位置的元素,remove(index):

如果删除的元素,不在队尾,则需要将原有队列,以index为界,分为前后两个部分,分别插入到新的数组中。

    /**
     * 删除指定位置的索引,实现逻辑为:首先创建一个新的数组,长度为原来数组-1,移动原来数组中,指定元素索引的前后两部分,到新的数组中
     * 如果删除的元素index ==length-1(最后一个),则直接复制1到length-1的元素到新的数组即可。
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).  Returns the element that was removed from the list.
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    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();
        }
    }

从队列中获取元素,get(index):

获取方法不加锁。

    // Positional Access Operations

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

    /**
     * 获取指定索引的元素,对元素读取时,不会进行 ReentrantLock 锁操作。
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E get(int index) {
        return get(getArray(), index);
    }

返回列表的迭代器,其实是返回内部类COWIterator实例

    /**
     * 返回内部类 COWIterator 实例
     * Returns an iterator over the elements in this list in proper sequence.
     *
     * <p>The returned iterator provides a snapshot of the state of the list
     * when the iterator was constructed. No synchronization is needed while
     * traversing the iterator. The iterator does <em>NOT</em> support the
     * {@code remove} method.
     *
     * @return an iterator over the elements in this list in proper sequence
     */
    public Iterator<E> iterator() {
        return new COWIterator<E>(getArray(), 0);
    }

    /**
     * 包含一个本列表的快照和初始化的游标,快照和本list相同,初始化游标为0,从头开始遍历
     * Returns an iterator over the elements in this list in proper sequence.
     *
     * <p>The returned iterator provides a snapshot of the state of the list
     * when the iterator was constructed. No synchronization is needed while
     * traversing the iterator. The iterator does <em>NOT</em> support the
     * {@code remove} method.
     *
     * @return an iterator over the elements in this list in proper sequence
     */
      private COWIterator(Object[] elements, int initialCursor) {
          cursor = initialCursor;
          snapshot = elements;
      }

返回list的listIterator迭代器:

    /**
     * {@inheritDoc}
     *
     * <p>The returned iterator provides a snapshot of the state of the list
     * when the iterator was constructed. No synchronization is needed while
     * traversing the iterator. The iterator does <em>NOT</em> support the
     * {@code remove}, {@code set} or {@code add} methods.
     */
    public ListIterator<E> listIterator() {
        return new COWIterator<E>(getArray(), 0);
    }

遍历对list中的元素进行调整:forEach():

    /**
     * 按照指定的action对list的元素进行处理
     */	
    public void forEach(Consumer<? super E> action) {
        if (action == null) throw new NullPointerException();
        Object[] elements = getArray();
        int len = elements.length;
        for (int i = 0; i < len; ++i) {
            @SuppressWarnings("unchecked") E e = (E) elements[i];
            action.accept(e);
        }
    }

保留指定list中包含的元素,对于当前list中其他的元素,则进行删除:

    /**
     * 删除当前列表中,元素未包含在指定列表c中的元素
     * Retains only the elements in this list that are contained in the
     * specified collection.  In other words, removes from this list all of
     * its elements that are not contained in the specified collection.
     *
     */
    public boolean retainAll(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();
        }
    }

添加元素时,看待添加的元素,是否已经存在于当前的列表中,如果已经存在,则不需要添加,如果不存在,才进行添加:

    /**
     * 如果指定的元素e在当前列表中不存在,则进行添加。否则返回false
     *
     * @param e element to be added to this list, if absent
     * @return {@code true} if the element was added
     */
    public boolean addIfAbsent(E e) {
        Object[] snapshot = getArray();
        return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
            addIfAbsent(e, snapshot);
    }
    private boolean addIfAbsent(E e, Object[] snapshot) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] current = getArray();
            int len = current.length;
            if (snapshot != current) {
                // Optimize for lost race to another addXXX operation
                int common = Math.min(snapshot.length, len);
                for (int i = 0; i < common; i++)
                    if (current[i] != snapshot[i] && eq(e, current[i]))
                        return false;
                if (indexOf(e, current, common, len) >= 0)
                        return false;
            }
            Object[] newElements = Arrays.copyOf(current, len + 1);
            newElements[len] = e;
            setArray(newElements);
            return true;
        } finally {
            lock.unlock();
        }
    }

根据指定的前后的索引位置,对当前列表进行截取:

针对于当前方法,需要格外注意的是,返回的列表,是建立在本列表的基础之上,任何对返回列表的修改操作,都会反映到本列表中。

    /**
     * 返回当前list在指定范围内的子列表,返回的列表依靠当前的列表,所以,对返回列表的修改,都会反映到当前的列表中。
     * Returns a view of the portion of this list between
     * {@code fromIndex}, inclusive, and {@code toIndex}, exclusive.
     * The returned list is backed by this list, so changes in the
     * returned list are reflected in this list.
     *
     * 不论当前列表经过什么方法被修改,只要不是经过返回列表进行修改,那么通过本方法返回的列表语义就会变成 undefined .
     * <p>The semantics of the list returned by this method become
     * undefined if the backing list (i.e., this list) is modified in
     * any way other than via the returned list.
     */
    public List<E> subList(int fromIndex, int toIndex) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray();
            int len = elements.length;
            if (fromIndex < 0 || toIndex > len || fromIndex > toIndex)
                throw new IndexOutOfBoundsException();
            return new COWSubList<E>(this, fromIndex, toIndex);
        } finally {
            lock.unlock();
        }
    }	

剩余的其他方法,不再赘述:

public boolean equals(Object arg0){}
public String toString(){}
public int hashCode(){}
public Object clone(){}
public int indexOf(Object arg0,int arg1){}
public int indexOf(Object arg0){}
public void clear(){}
public boolean isEmpty(){}
public int lastIndexOf(Object arg0){}
public int lastIndexOf(Object arg0,int arg1){}
public boolean contains(Object arg0){}
public void replaceAll(UnaryOperator arg0){}
public int size(){}
public Object[] toArray(Object[] arg0){}
public Object[] toArray(){}
public boolean addAll(int arg0,Collection arg1){}
public Object set(int arg0,Object arg1){}
public boolean containsAll(Collection arg0){}
public boolean removeAll(Collection arg0){}
public ListIterator listIterator(){}
public ListIterator listIterator(int arg0){}
public boolean removeIf(Predicate arg0){}
public void sort(Comparator arg0){}
public final void wait(long arg0,int arg1) throws InterruptedException{}
public final native void wait(long arg0) throws InterruptedException{}
public final void wait() throws InterruptedException{}
public final native Class getClass(){}
public final native void notify(){}
public final native void notifyAll(){}
public Stream stream(){}
public Stream parallelStream(){}

遗留问题:

subList()方法注释中:
     * 不论当前列表经过什么方法被修改,只要不是经过返回列表进行修改,那么通过本方法返回的列表语义就会变成 undefined .
     * <p>The semantics of the list returned by this method become
     * undefined if the backing list (i.e., this list) is modified in
     * any way other than via the returned list.


具体指的是什么意思?

 

其他相关文章:

Java集合类框架源码分析 之 Stack源码解析 【9】

Java集合类框架源码分析 之 Vector源码解析 【8】

Java集合类框架源码分析 之 AttributeList源码解析 【7】

Java集合类框架源码分析 之 RoleList源码解析 【6】

Java集合类框架源码分析 之 CopyOnWriteArrayList源码解析 【5】

Java集合类框架源码分析 之 LinkedList源码解析 【4】

Java集合类框架源码分析 之 ArrayList源码解析 【3】

Java集合类框架源码分析 之 接口中是否可以有方法实现 【2】

Java集合类框架源码分析 之 List 接口源码分析 【1】

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值