我是靠谱客的博主 光亮电源,最近开发中收集的这篇文章主要介绍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所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复