参见: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>();