我是靠谱客的博主 缓慢中心,最近开发中收集的这篇文章主要介绍CopyOnWriteArrayList为何能循环删除,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

和ArrayList相比,CopyOnWriteArrayList是线程安全的,同时在for循环中删除时,CopyOnWriteArrayList是没有问题的,而ArrayList会删除不全或报错。

例如在循环删除时:

@org.junit.Test
public void t_copyWrite() {

    CopyOnWriteArrayList list = new CopyOnWriteArrayList<>();
    list.add("a");
    list.add("ab");
    // 不会报错
    for (Object o : list) {
        list.remove(o);
    }

    System.out.println("list = " + list);

    ArrayList arrayList = new ArrayList<String>();

    arrayList.add("a");
    arrayList.add("ab");
    arrayList.add("abc");

    for (Object o : arrayList) {
       // 会报错        
        arrayList.remove(o);
        // 不会报错,原因后面会解释
        if ("ab".equals(o)) {
            arrayList.remove(o);
        }
    }

    System.out.println("arrayList = " + arrayList);
}

for循环会经过编译转成

ArrayList arrayList = new ArrayList();
arrayList.add("a");
arrayList.add("ab");
arrayList.add("abc");
Iterator var6 = arrayList.iterator();

while(var6.hasNext()) {
    Object o = var6.next();
    if ("abc".equals(o)) {
        arrayList.remove(o);
    }
}

问题就出现在 modCount != expectedModCount 这个判断上。

// java.util.ArrayList.Itr
public boolean hasNext() {
    // 不等于size就会返回true, size是在ArrayList中,是实时更新的。 如果是倒数第二个,刚好coursor==size。则返回false也就不会执行next()方法,刚好不会报错
    return cursor != size; 
}
// java.util.ArrayList.Itr#next
public E next() {
    checkForComodification();
    int i = cursor;
    if (i >= size)
        throw new NoSuchElementException();
    Object[] elementData = ArrayList.this.elementData;
    if (i >= elementData.length)
        throw new ConcurrentModificationException();
    cursor = i + 1;
    return (E) elementData[lastRet = i];
}
// java.util.ArrayList.Itr#checkForComodification
final void checkForComodification() {
    if (modCount != expectedModCount) // modCount 还是原来的
        throw new ConcurrentModificationException();
}

// java.util.ArrayList#fastRemove
private void fastRemove(int index) {
    modCount++;           // 修改了 modCount
    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work
}

再看一下CopyOnWriteArrayList

// java.util.concurrent.CopyOnWriteArrayList.COWIterator#hasNext
public boolean hasNext() {
    return cursor < snapshot.length;
}

由于CopyOnWriteArrayList 摒弃了 modCount 与 expectedModCount ,每次删除后,都是重新 setArray(newElements); 所以避免了ArrayList的情况。

最后

以上就是缓慢中心为你收集整理的CopyOnWriteArrayList为何能循环删除的全部内容,希望文章能够帮你解决CopyOnWriteArrayList为何能循环删除所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(73)

评论列表共有 0 条评论

立即
投稿
返回
顶部