ConcurrentHashMap实现分析

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

你可能感兴趣的:(java,多线程,Concurrent)