ArrayList之坑点
来源:互联网 发布:算法导论第四版 pdf 编辑:程序博客网 时间:2024/05/17 02:15
ConcurrentModificationException异常
详细原因参见 http://www.cnblogs.com/dolphin0520/p/3933551.html
缘起iterator
简单来说:在iterator中遍历以及删除时都会去执行如下检查
final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); }
modCount 就是modify count 对队列修改的次数。
那么expectedModCount是什么时候赋予的呢?
public Iterator<E> iterator() { return new Itr(); } private class Itr implements Iterator<E> { int cursor; // index of next element to return int lastRet = -1; // index of last element returned; -1 if no such int expectedModCount = modCount;
在Iterator对象初始化的时候就赋予了当前的modCount值,如果这之后在执行iterator.next() 的同时,还去调用list.add或remove操作,那么肯定会出现expectedModCount != modCount的情况,从而导致异常产生。
仅仅只是iterator?牵出foreach
被广泛使用的foreach,其实间接的就是使用iterator实现的。(在JDK中没法看到具体实现,反编译可以看到字节码窥探到) 参见 http://blog.csdn.net/a596620989/article/details/6930479
为什么作者要这么做呢?
在遍历的时候他不希望队列在别的线程里还进行队列的修改,也就是说在设计的时候没有考虑多线程同步问题,然后用这种条件来限制。
该如何解决
很弱的办法
在删除的时候使用iterator的remove ,因为他进行删除的时候,会同步一下modCount的值给expectedModCount。
public void remove() { if (lastRet < 0) throw new IllegalStateException(); checkForComodification(); try { ArrayList.this.remove(lastRet); cursor = lastRet; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } }
这个只能说解决了一小部分问题。遇到多线程还是有问题。
最后有2种解决办法:
1)在使用iterator迭代的时候使用synchronized或者Lock进行同步;
用这种同步锁的方式来阻止modCount不一致的情况发生。这个办法直接,但是需要自己手动添加锁。
2)使用并发容器CopyOnWriteArrayList代替ArrayList和Vector。见http://blog.csdn.net/xude1985/article/details/51418558
addAll
public boolean addAll(Collection<? extends E> c) { Object[] a = c.toArray(); int numNew = a.length; ensureCapacityInternal(size + numNew); // Increments modCount System.arraycopy(a, 0, elementData, size, numNew); size += numNew; return numNew != 0; }
虽然我们看到有arraycopy,但是他复制的只是对象引用,而作为被指向的目标:对象数据则是没有任何改变。addAll只是浅拷贝而已,并没有进行深拷贝,所以你在改变对象内部数据的时候,仍旧是一变都变的
add
public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
add时候并没有给你进行去重,所以你需要在调用add前自己去重
- ArrayList之坑点
- ArrayList 关键点分析
- LinkedList和ArrayList异同点
- Java学习之ArrayList
- Java学习之ArrayList
- 链表之ArrayList
- Java集合之ArrayList
- 集合之ArrayList
- 类实现之ArrayList
- 源码分析之ArrayList
- java集合之ArrayList
- jdk1.6之ArrayList
- Java集合之ArrayList
- java 之ArrayList实现
- java集合之ArrayList
- C# 之 集合ArrayList
- java集合之arrayList
- 实验田之打印ArrayList
- RxJava之组合操作符
- javaweb防止当前表单重复提交数据
- 多余元素删除之移位算法
- Java字节码操纵框架ASM快速入门
- 自己做的萌萌哒的js宠物挂件~
- ArrayList之坑点
- vi文本编辑器
- Docker 安全
- Log4j详细配置
- 安装OS X虚拟机错误vcpu-0
- 带你玩转Visual Studio——VS2015的新功能和特性
- 百度之星预选赛1003字典树模板
- [POJ1083]Moving Tables
- C++:将一元人民币兑换成1、2、5分的硬币,求换法