java5中新增了ConcurrentMap接口和它的一个实现类ConcurrentHashMap.该类在多线程并发情况下的效率要比HashTable和Collections.synchronizedMap()返回的map效率要高。原因是它的锁实现的很“机智”。
HashTable和Collections的内部类SynchronizedMap里的同步,都是用synchronized来实现的,每次都是锁整个表,因此同一时刻只能有一个线程操作hash表。
而ConcurrentHashMap中使用了Segment[]来存储数据,Segment继承自ReentrantLock类(这样执行lock操作就方便了),默认情况下有16个Segment,当put数据时,会看这个key的hash值对应到哪个Segment里面,然后只锁这个Segement,所以它允许多个线程同时put。(读操作一般不需要加锁,除非发生特殊情况)
Segemnt
/**
* The segments, each of which is a specialized hash table
*/
final Segment<K,V>[] segments;
/**
* Segments are specialized versions of hash tables. This
* subclasses from ReentrantLock opportunistically, just to
* simplify some locking and avoid separate construction.
*/
static final class Segment<K,V> extends ReentrantLock implements Serializable {
ConcurrentHashMap的put()方法:
public V put(K key, V value) {
if (value == null)
throw new NullPointerException();
int hash = hash(key.hashCode());
return segmentFor(hash).put(key, hash, value, false);
}
/**
* Returns the segment that should be used for key with given hash
* @param hash the hash code for the key
* @return the segment
*/
final Segment<K,V> segmentFor(int hash) {
return segments[(hash >>> segmentShift) & segmentMask];
}
先根据key的hash值计算所属的Segment,然后执行该Segment的put()方法。
Segemnt的put()方法:
V put(K key, int hash, V value, boolean onlyIfAbsent) {
lock();
try {
int c = count;
if (c++ > threshold) // ensure capacity
rehash();
HashEntry<K,V>[] tab = table;
int index = hash & (tab.length - 1);
HashEntry<K,V> first = tab[index];
HashEntry<K,V> e = first;
while (e != null && (e.hash != hash || !key.equals(e.key)))
e = e.next;
V oldValue;
if (e != null) {
oldValue = e.value;
if (!onlyIfAbsent)
e.value = value;
}
else {
oldValue = null;
++modCount;
tab[index] = new HashEntry<K,V>(key, hash, first, value);
count = c; // write-volatile
}
return oldValue;
} finally {
unlock();
}
}
由于Segment继承自ReentrantLock,因此可以很方便的调用lock()和unlock().
综述,由于ConcurrentHashMap采用了分段锁(或者说锁分离),并且对存储size等操作做了一些加锁优化,因此其效率要高一些。重点还是分段锁。
有一篇介绍ConcurrentHashMap的文章,分享一下:
http://www.iteye.com/topic/344876