我是靠谱客的博主 光亮电源,最近开发中收集的这篇文章主要介绍CopyOnWriteArrayList(遍历中删除元素)CopyOnWriteArrayList,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

CopyOnWriteArrayList

在之前的像素鸟游戏中我遇到一个问题,我想要在遍历List的同时根据一定条件删除List中的元素。

但是有一个问题,我们不能在遍历一个List的同时对于其内的元素进行删改的操作。

这时候会给出这样的错误:

java.util.ConcurrentModificationException

我不想使用迭代的方式完成这个功能,那样很麻烦,难道我不能使用List把这个问题解决么?

这个时候我了解了一个List的实现类CopyOnWriteArrayList。

public class CopyOnWriteArrayList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable

CopyOnWrite这几个单词很好理解,那么他是怎么实现在循环内完成对于遍历中数据的删除的呢?

其实不难猜测,应该是使用copy一个新的List进行增删改的操作,循环结束再进行复制。

让我们看一下源码

public boolean remove(Object o) {
    Object[] snapshot = getArray();
    int index = indexOf(o, snapshot, 0, snapshot.length);
    return (index < 0) ? false : remove(o, snapshot, index);
}

果不其然。

到这已经完成了我们的需求,但是看到这里不妨继续看看它还进行了怎样的封装。

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还提供了索引删除的方式,并且进行了加锁处理,可以想见CopyOnWriteArrayList类是支持多线程操作的。

看到这里我有点儿小蒙,既然移除索引位置对象需要保证线程安全,那么为什么对于对象的移除却并没有呢?仔细看源码我发现再其中调用了另一个remove函数。

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

在这个重载函数中才真正的进行了多线程处理。

最后

以上就是光亮电源为你收集整理的CopyOnWriteArrayList(遍历中删除元素)CopyOnWriteArrayList的全部内容,希望文章能够帮你解决CopyOnWriteArrayList(遍历中删除元素)CopyOnWriteArrayList所遇到的程序开发问题。

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

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

评论列表共有 0 条评论

立即
投稿
返回
顶部