ConcurrentHashMap vs Collections.synchronizedMap() (转)
之前在
然后看了下面这篇文章,讲的还是非常清晰的,所以摘抄过来,原文地址http://www.pixelstech.net/article/1394026282-ConcurrentHashMap-vs-Collections-synchronizedMap()
ConcurrentHashMap and Collections.synchronizedMap() both provide thread-safe operations of collections of data. They are used in multithreaded programs to provide both thread safety and performance improvements. In many cases, we can use either of them.
But the realization of thread safety is different for these two implementations. ConcurrentHashMap will create an HashEntry[] array internally to store the elements passed in from a Map, while Collections.synchronizedMap() will return a SynchronizedMap.
The main difference between these two is that ConcurrentHashMap will lock only portion of the data which are being updated while other portion of data can be accessed by other threads. However, Collections.synchronizedMap() will lock all the data while updating, other threads can only access the data when the lock is released. If there are many update operations and relative small amount of read operations, you should choose ConcurrentHashMap.
Also one other difference is that ConcurrentHashMap will not preserve the order of elements in the Map passed in. It is similar to HashMap when storing data. There is no guarantee that the element order is preserved. While Collections.synchronizedMap(0 will preserve the elements order of the Map passed in. For example, if you pass a TreeMap to ConcurrentHashMap, the elements order in the ConcurrentHashMap may not be the same as the order in the TreeMap, but Collections.synchronizedMap() will preserve the order.
Furthermore, ConcurrentHashMap can guarantee that there is no ConcurrentModificationException thrown while one thread is updating the map and another thread is traversing the iterator obtained from the map. However, Collections.synchronizedMap() is not guaranteed on this. If we obtain an Iterator from Collections.synchronizedMap() by calling map.keySet().iterator() and then traverse the iterator, at the same time if another thread is trying to updating the map by calling map.put(K,V), we will get a ConcurrentModificationException.
Map<String,String> map = Collections.synchronizedMap(new TreeMap<String,String>());
map.put("key1","value1");
map.put("key2","value2");
map.put("key3","value3");
Set<Entry<String,String>> entries = map.entrySet();
Iterator<Entry<String,String>> iter = entries.iterator();
while(iter.hasNext()){
System.out.println(iter.next()); //Will throw ConcurrentModificationException
map.remove("key2");
}
Now I am wondering whether there is one object which can preserve the insertion order of elements like Collections.synchronizedMap() and also doesn't throw ConcurrentModificationException like ConcurrentHashMap. Fortunately since 1.6 there is a class called ConcurrentSkipListMap which can fulfill these two requirements, from the documentation, we can find that ConcurrentSkipListMap will not throw ConcurrentModificationException and also it will preserve the insertion order of the Map passed in. The only drawback it may have is its performance.
You can also check the difference between ConcurrentHashMap and Hashtable for more understanding about ConcurrentHashMap.
由于这篇纯英文,所以我稍微简单点解释一下区别
第一点
ConcurrentHashMap 在update 时候锁 各自的bucket, 在 bucket较多时 性能提示较之明显
Collections.synchronizedMap() 是锁整张表,多个update情况下只能wait咯
第二点
ConcurrentHashMap 不保存顺序 就如hashmap一样,但是Collections.synchronizedMap()是保存的,在jdk6 后 并发跳跃表支持保存顺序,但相应的tradeoff some performance(折衷了一些性能),sigh...
第三点
ConcurrentHashMap 没有采取fast-fail 策略(快速失败,例如各种集合框架暗存modcount字段来标记travese时候是否被更新了,更新之后就抛出异常),而是采取类似于CopyOnWriteArrayList的重新生成对象策略,当然这样可能读到旧数据,但是木有办法的咯
Collections.synchronizedMap() 则抛出ConcurrentModificationException异常
木有啦,如有不对,还请指正(^o^)/~
Collections.synchronizedMap()和Hashtable都是锁定整个map,他们是相对线程安全。单个对map的操作可以看做是"原子的",是线程安全的。但是如果多个操作序列组合到一起可能就是线程不安全了。
Hashtable hashtable=new Hashtable();
if(!hashtable.containsKey("key")) 1
{
Thread.yield(); //效果更明显些
hashtable.put("key", "value"); 2
}
线程A 执行完1处后,正好有一个线程B也执行完1处。 线程Aput进“value”后,线程B又put进“value1”,就不是线程安全了。 可以将该段代码放到同步代码块中。
在concurrentHashMap中 concurrentMap.putIfAbsent("key", "value");不会存在线程安全问题
至于putIfAbsent函数。他也是使用了静态代码块,这是他锁定的是map的一部分(就是一个segment锁桶),其他线程依旧可以访问其他部分。相比于hashtable效率会高上很多
synchronized (f) {
if (tabAt(tab, i) == f) {
if (fh >= 0) {
binCount = 1;
for (Node e = f;; ++binCount) {
K ek;
if (e.hash == hash &&
((ek = e.key) == key ||
(ek != null && key.equals(ek)))) {
oldVal = e.val;
if (!onlyIfAbsent)
e.val = value;
break;
}
Node pred = e;
if ((e = e.next) == null) {
pred.next = new Node(hash, key,
value, null);
break;
}
}
}
else if (f instanceof TreeBin) {
Node p;
binCount = 2;
if ((p = ((TreeBin)f).putTreeVal(hash, key,
value)) != null) {
oldVal = p.val;
if (!onlyIfAbsent)
p.val = value;
}
}
}
}
if (binCount != 0) {
if (binCount >= TREEIFY_THRESHOLD)
treeifyBin(tab, i);
if (oldVal != null)
return oldVal;
break;
}
}
}