参见:http://zl198751.iteye.com/blog/907927
ConcurrentModificationException
在这种迭代方式中,当iterator被创建后集合再发生改变就不再是抛出ConcurrentModificationException,取而代之的是在改变时new新的数据从而不影响原有的数据 ,iterator完成后再将头指针替换为新的数据 ,这样iterator线程可以使用原来老的数据,而写线程也可以并发的完成改变。
左边便是Hashtable的实现方式---锁整个hash表;而右边则是ConcurrentHashMap的实现方式---锁桶(或段)。 ConcurrentHashMap将hash表分为16个桶(默认值),诸如get,put,remove等常用操作只锁当前需要用到的桶。试想,原来只能一个线程进入,现在却能同时16个写线程进入(写线程才需要锁定,而读线程几乎不受限制,之后会提到),并发性的提升是显而易见的。
更令人惊讶的是ConcurrentHashMap的读取并发,因为在读取的大多数时候都没有用到锁定,所以读取操作几乎是完全的并发操作,而写操作锁定的粒度又非常细,比起之前又更加快速(这一点在桶更多时表现得更明显些)。只有在求size等操作时才需要锁定整个表。而在迭代时,ConcurrentHashMap使用了不同于传统集合的快速失败迭代器(见之前的文章《JAVA API备忘---集合》)的另一种迭代方式,我们称为弱一致迭代器。在这种迭代方式中,当iterator被创建后集合再发生改变就不再是抛出ConcurrentModificationException,取而代之的是在改变时new新的数据从而不影响原有的数据,iterator完成后再将头指针替换为新的数据,这样iterator线程可以使用原来老的数据,而写线程也可以并发的完成改变,更重要的,这保证了多个线程并发执行的连续性和扩展性,是性能提升的关键。
示例:
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class MapConcurrenceDemo {
private static Map<String, String> map = new HashMap<String, String>();
static{
for(int i=0;i<1000;i++){
String str = String.valueOf(i);
map.put(str, str);
}
}
public static void main(String[] args) {
new Thread(new MapListThread(map)).start();
new Thread(new MapRemoveThread(map)).start();
}
}
class MapListThread implements Runnable{
private Map<String, String> map;
public MapListThread(Map<String, String> map){
this.map = map;
}
public void run() {
Iterator<String> iter = map.values().iterator();
while(iter.hasNext()){
iter.next();
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
class MapRemoveThread implements Runnable{
private Map<String, String> map;
public MapRemoveThread(Map<String, String> map){
this.map = map;
}
public void run() {
for(int i=200;i<900;i++){
String str = String.valueOf(i);
map.remove(str);
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Remove OK. map.size:"+map.size());
}
}执行结果:
Exception in thread "Thread-0" java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793) at java.util.HashMap$ValueIterator.next(HashMap.java:822) at com.effective.object.MapListThread.run(MapConcurrenceDemo.java:29) at java.lang.Thread.run(Thread.java:619) Remove OK. map.size:300
如果把map的实现类改为ConcurrentHashMap,就不会出现上面的错误,如下:
private static Map<String, String> map = new ConcurrentHashMap<String, String>();