JAVA面试基础篇(JAVA集合)(二)之CopyOnWriteArrayList源码解读

目录

 

 

CopyOnWriteArrayList介绍

构造

成员方法

新增:

删除:

第一步拷贝  System.arraycopy(elements, 0, newElements, 0, index);

第二部拷贝  System.arraycopy(elements, index + 1, newElements, index,

                                 numMoved);

查询:

优点和缺点

优点:

     缺点:


 

CopyOnWriteArrayList介绍

首先看下类上的注释,

/**
 * 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.
 *
 * <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.
 *
 * <p>This class is a member of the
 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
 * Java Collections Framework</a>.
 *
 * @since 1.5
 * @author Doug Lea
 * @param <E> the type of elements held in this collection
 */

Doug Lea写的很清楚哈,这个是ArrayList的一个所有操作都是线程安全类,这个线程安全是通过拷贝了一个数组实

构造

1.先看下他里面有哪些成员变量吧:

 一个锁:

 /** The lock protecting all mutators */
 final transient ReentrantLock lock = new ReentrantLock();

一个数组

 /** The array, accessed only via getArray/setArray. */
    private transient volatile Object[] array;

OK,That’s all.

成员方法

       既然是个集合,那么就看下他的增删改查的方法。

新增:

    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#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();
        }
    }

       我来翻译一下注释:在这个列表的最后添加这个特殊的元素

看他刚进方法的时候就拿了这个成员变量的锁,你这里不奇怪,为什么不直接用this.lock.lock(),HAHA,看到final就该明白是为了“安全”。

       接着,他这里拷贝了一份完整的数组,还把容量拓展了1个         

Object[] newElements = Arrays.copyOf(elements, len + 1);

其实他的赋值是在新的数组完成的:newElements[len] = e;

最后直接把这个数组的引用给到这个对象的array,瞄一眼setArray

 

 

删除:

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

和新增一样,CopyOnWriteArrayList在执行删除操作的时候,新建了一个数组

拷贝的时候分了两部:

第一步拷贝  System.arraycopy(elements, 0, newElements, 0, index);

0~index的数组元素

第二部拷贝  System.arraycopy(elements, index + 1, newElements, index,

                                 numMoved);

index+1 ~ len的数组元素。

       最后赋值。

      

查询:

       OK,把两个get兄弟拿出来

    // Positional Access Operations

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

    /**
     * {@inheritDoc}
     *
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */
    public E get(int index) {
        return get(getArray(), index);
    }

写到这里,大家应该明白了,更新的方法我就不再赘述了,CopyOnWriteArrayList所谓的线程安全的实质,修改对象的时候是通过锁(Lock数组拷贝的方式来完成的,最后只是将新的数组地址赋给了CopyOnWriteArrayList内置的数组;而每次线程去查询的时候获取的是对象内置的数组array,且读操作不需要加锁.

优点和缺点

优点:

相对于Vector这种操作完全安全的集合,或者使用Collections. synchronizedList来说,他的性能会更优;体现在读元素无锁上。

对于队列的读多余写的场景CopyOnWriteArrayList是个不错的选择。

     缺点:

         CopyOnWriteArrayList的每次更新,新增,删除等操作都会新建一个数组,如数组长度本身很长,这将是一笔不菲的开销。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

轩渃

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值