如何产生,一边遍历一边修改元素,产生iter后再修改原结构,如下,无论是for中或iter都会产生ConcurrentModificationException
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List; /**
* Created by itworker365 on 5/16/2017.
*/
public class ConcurrentModifyException {
public static void main(String[] args) throws InterruptedException {
List<String> a = new ArrayList<String>();
a.add("a");
a.add("b");
a.add("c");
final List<String> list = new ArrayList<String>(a);
final Iterator<String> it = list.iterator();
//cause ConcurrentModifyException,list.iterator已经生成iterator对象,此时再更改原结构报错
a.add("d");
Thread t = new Thread(new Runnable() {
int count = -1;
@Override
public void run() {
if (list.contains("a")) {
list.remove("a");
}
}
});
t.setDaemon(true);
t.start(); for (String s : list) {
//cause ConcurrentModifyException,边读边改报错
System.out.println(list.hashCode() + " " + s);
}
// while (it.hasNext()) {
// //cause ConcurrentModifyException,边读边改报错
// System.out.println(it.next());
// }
}
}
产生原因:
public E next() {
checkForComodification();
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
解决办法:
1. 用CopyOnWriteArrayList, 可以发现在打印hashcode的时候并不相同,这种结构在修改元素时使用Arrays.CopyOf复制元素,然后在新List中修改之后修改引用
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; /**
* Created by itworker365 on 5/16/2017.
*/
public class ConcurrentModifyException {
public static void main(String[] args) throws InterruptedException {
List<String> a = new ArrayList<String>();
a.add("a");
a.add("b");
a.add("c");
final List<String> list = new CopyOnWriteArrayList<String>(a);
final Iterator<String> it = list.iterator();
Thread t = new Thread(new Runnable() {
int count = -1;
@Override
public void run() {
if (list.contains("a")) {
list.remove("a");
}
}
});
t.setDaemon(true);
t.start();
for (String s : list) {
System.out.println(list.hashCode() + " " + s);
}
while (it.hasNext()) {
System.out.println(it.next());
}
}
}
CopyOnWriteArrayList关键实现,一看既懂,需要注意的是内存使用,可能复制后会出发gc,因为写操作完成并且引用指向新数组之前,其他并发读取线程只能看到旧数据,所以只是最终一致性,不能实时。
private volatile transient Object[] array;
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();
}
}
final void setArray(Object[] a) {
array = a;
}
2. 使用Iterator去除,迭代器支持的功能有限
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; /**
* Created by itworker365 on 5/16/2017.
*/
public class ConcurrentModifyException {
public static void main(String[] args) throws InterruptedException {
List<String> a = new ArrayList<String>();
a.add("a");
a.add("b");
a.add("c");
final List<String> list = new ArrayList<String>(a);
final Iterator<String> it = list.iterator();
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while (it.hasNext()) {
String xx = it.next();
it.remove();
}
}
});
t.setDaemon(true);
t.start();
while (it.hasNext()) {
System.out.println(it.next());
}
}
}