JDK1.6中ConcurrentHashMap源码阅读

1、ConcurrentHashMap结构图:

      

2、ConcurrentHashMap类图

      

   1、HashEntry类

//ConcurrentHasHap存储最小单元
static final class HashEntry<K,V> {
 //key-value中的key值,是不可变的
        final K key;
 //key通过hash算法生成的hash值,是不可变的
        final int hash;
        //key-value的value值,value是可变的,但是保持可见性。
        volatile V value;
        //HashEntry的下一个节点
        final HashEntry<K,V> next;

        HashEntry(K key, int hash, HashEntry<K,V> next, V value) {
            this.key = key;
            this.hash = hash;
            this.next = next;
            this.value = value;
        }

//返回一个HashEntry数组
static final <K,V> HashEntry<K,V>[] newArray(int i) {
	    return new HashEntry[i];
	}
}
 

 2、Segment内部类

      该类继承于ReentrantLock类,实现序列化接口。对每个HashEntry修改在整个

table上加锁(也就是在segment上进行加锁)。
static final class Segment<K,V> extends ReentrantLock implements Serializable 
  segment字段:
该segment段内拥有的HashEntry数量。
transient volatile int count;
        table被修改的次数计数器(segment中,put,remove方法会修改该值)。读该segment内table的size, 如果获取size前和获取size后的modCount不同,则说明有另外线程修改了segment的table,获取的改size的snapshot不正确,size计算具体见size方法
transient int modCount;
  超过threshold,就会进行rehash
transient int threshold;
  每个segment存的HasnEntry的数组
transient volatile HashEntry<K,V>[] table;
  负载因子,threshold = Table.length * loadFactor;
final float loadFactor;
 

方法:

1、返回table数据中的hashEntry

HashEntry<K,V> getFirst(int hash) {
            HashEntry<K,V>[] tab = table;
            return tab[hash & (tab.length - 1)];//2的倍数求余
}
 2、 整个table加锁返回指定HashEntry的value值
V readValueUnderLock(HashEntry<K,V> e) {
            lock();
            try {
                return e.value;
            } finally {
                unlock();
            }
        }
 3、 根据key和hash值,获取相应value,读的时候并未加锁
V get(Object key, int hash) {
            //判断table中的HashEntry数量是否为0,注意count是可见的(volatile )
            if (count != 0) { // read-volatile
            //根据hash获取table中数组中的HashEntry
                HashEntry<K,V> e = getFirst(hash);
                while (e != null) {
       //hash冲突,hash值和key值都相同,则可定位该HashEntry是key相对应的HashEntry。
                    if (e.hash == hash && key.equals(e.key)) {
                        V v = e.value;
                        if (v != null)
                            return v;
                        //value为空,则在锁状态下继续读一次
                        return readValueUnderLock(e); // recheck
                    }
                    //hash冲突,链表向下移动指针
                    e = e.next;
                }
            }
            return null;
        }
     4、判断是否包含该value,读的时候并未加锁     
boolean containsValue(Object value) {
            if (count != 0) { // read-volatile
                HashEntry<K,V>[] tab = table;
                int len = tab.length;
                //遍历table中的每一个值
                for (int i = 0 ; i < len; i++) {
                    //遍历链表中的每一个值
                    for (HashEntry<K,V> e = tab[i]; e != null; e = e.next) {
                        V v = e.value;
                        //value为null的话,进行double check 
                        if (v == null) // recheck
                            v = readValueUnderLock(e);
                        if (value.equals(v))
                            return true;
                    }
                }
            }
            return false;
        }
     replace相应HashEntry的value,修改要加锁,注意,这里try-finally语句,unlock写在finally中
boolean replace(K key, int hash, V oldValue, V newValue) {
            lock();
            try {
                //找到key和hash值都相同的HashEntry
                HashEntry<K,V> e = getFirst(hash);
                while (e != null && (e.hash != hash || !key.equals(e.key)))
                    e = e.next;
                boolean replaced = false;
                //找到相应的HashEntry,如果值与旧值相同,value修改为新的值
                if (e != null && oldValue.equals(e.value)) {
                    replaced = true;
                    e.value = newValue;
                }
                return replaced;
            } finally {
                unlock();
            }
        }
   put方法,奇怪的是不会HashEntry链表中增加
V put(K key, int hash, V value, boolean onlyIfAbsent) {
            lock();
            try {
                int c = count;
                //当前count超过threshold,则进行rehash
                if (c++ > threshold) // ensure capacity
                    rehash();
                //获取table数组中的HashEntry
                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) {
                //有key值一样的hashEntry,保存旧的value值并返回,覆盖旧的value
                    oldValue = e.value;
                    if (!onlyIfAbsent)
                        e.value = value;
                }
                else {
                //key匹配到的HashEntry为空,新建HashEntry,并存入table中
                    oldValue = null;
                    ++modCount;//增加HashEntry节点,修改modCount的值
                    tab[index] = new HashEntry<K,V>(key, hash, first, value)
                    count = c; // write-volatile
                }
                return oldValue;
            } finally {
                unlock();
            }
        }
  rehash方法
void rehash() {
   //rehash后的长度不可以大于MAXIMUM_CAPACITY
            HashEntry<K,V>[] oldTable = table;
            int oldCapacity = oldTable.length;
            if (oldCapacity >= MAXIMUM_CAPACITY)
                return;
            //新的table是之前的两倍大
            HashEntry<K,V>[] newTable = HashEntry.newArray(oldCapacity<<1);
            threshold = (int)(newTable.length * loadFactor);
            int sizeMask = newTable.length - 1;
            //对于table数组中不为null的HashEntry进行rehash
            for (int i = 0; i < oldCapacity ; i++) {
                // We need to guarantee that any existing reads of old Map can
                //  proceed. So we cannot yet null out each bin.
                HashEntry<K,V> e = oldTable[i];
   
                if (e != null) {
                    //重新计算table数组中HashEntry节点的hash值。
                    HashEntry<K,V> next = e.next;
                    int idx = e.hash & sizeMask;
                    //如果该节点是单一节点,则修改节点在hashtable中位置
                    //  Single node on list
                    if (next == null)
                        newTable[idx] = e;
                    else {
    //该节点不是单一节点,next不为null,则找到lastRun的位置(链中可进行rehash的最后一个HashEntry)
                        // Reuse trailing consecutive sequence at same slot
                        HashEntry<K,V> lastRun = e;
                        int lastIdx = idx;
                        for (HashEntry<K,V> last = next;
                             last != null;
                             last = last.next) {
                            int k = last.hash & sizeMask;
                            if (k != lastIdx) {
                                lastIdx = k;
                                lastRun = last;
                            }
                        }
                        newTable[lastIdx] = lastRun;
                        //复制链中的可进行rehash的HashEntry到新的HashTable中
                        // Clone all remaining nodes
                        for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
                            int k = p.hash & sizeMask;
                            HashEntry<K,V> n = newTable[k];
                            newTable[k] = new HashEntry<K,V>(p.key, p.hash,
                                                             n, p.value);
                        }
                    }
                }
            }
            table = newTable;
        }
  移除节点
V remove(Object key, int hash, Object value) {
            lock();
            try {
                int c = count - 1;
   //寻找要移除的节点e
                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 = null;
                if (e != null) {
                    V v = e.value;
//如果e的值为null或者与希望移除value值一样
                    if (value == null || value.equals(v)) {
                        oldValue = v;
                        // All entries following removed node can stay
                        // in list, but all preceding ones need to be
                        // cloned.
                        ++modCount;
    //记录e后面那一个节点
                        HashEntry<K,V> newFirst = e.next;
                         //e节点前面的节点进行重新创建(为什么???),最后节点指向e的后面节点
    for (HashEntry<K,V> p = first; p != e; p = p.next)
                            newFirst = new HashEntry<K,V>(p.key, p.hash,
                                                          newFirst, p.value);
                        
    tab[index] = newFirst;
                        count = c; // write-volatile
                    }
                }
                return oldValue;
            } finally {
                unlock();
            }
        }
  ConcurrentHashMap方法
public ConcurrentHashMap(int initialCapacity,
                             float loadFactor, int concurrencyLevel) {
        //判断非法参数
        if (!(loadFactor > 0) || initialCapacity < 0 || concurrencyLevel <= 0)
            throw new IllegalArgumentException();

        if (concurrencyLevel > MAX_SEGMENTS)
            concurrencyLevel = MAX_SEGMENTS;

          //sshift用于统计,共进行了多少次2倍数的扩大
         //segment size大小
        // Find power-of-two sizes best matching arguments
        int sshift = 0;
        int ssize = 1;
        while (ssize < concurrencyLevel) {
            ++sshift;
            ssize <<= 1;
        }
        //segment大小没有用到的高位,据说用来计算用到的segment??
        segmentShift = 32 - sshift;
        //segment的大小
 segmentMask = ssize - 1;
 //创建segment数据
        this.segments = Segment.newArray(ssize);

        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
  //segment中,每个hashmap值的大小,先算出c,每个容器该有的大小,然后算出一个小于c的二的整数倍cap,做为每个hashmap大小
        int c = initialCapacity / ssize;
        if (c * ssize < initialCapacity)
            ++c;
        int cap = 1;
        while (cap < c)
            cap <<= 1;
        //为每个segment创建hashmap
        for (int i = 0; i < this.segments.length; ++i)
            this.segments[i] = new Segment<K,V>(cap, loadFactor);
    }
  size()方法
 public int size() {
        final Segment<K,V>[] segments = this.segments;
        //size大小
        long sum = 0;
        long check = 0;
 //每个segment的modCount
        int[] mc = new int[segments.length];
    	//尝试两次计算size大小,RETRIES_BEFORE_LOCK为2
        for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {
     //第二次统计size大小
            check = 0;
            //第一次统计size大小
            sum = 0;
            int mcsum = 0;
            for (int i = 0; i < segments.length; ++i) {
                //计算size大小
                sum += segments[i].count;
  //计算每个segment的modcount和
                mcsum += mc[i] = segments[i].modCount;
            }
     //如果mcsum为0,说明ConcurrentHashMap为空
            if (mcsum != 0) {
                for (int i = 0; i < segments.length; ++i) {
//再次计算size大小
                    check += segments[i].count;
//对比modCount是否有对ConcurrentHashMap修改,如果有,跳出循环,强制重试
                    if (mc[i] != segments[i].modCount) {
                        check = -1; // force retry
                        break;
                    }
                }
            }
     //如果两次统计大小一样,则跳出循环
            if (check == sum)
                break;
        }
 //如果两次统计都不成功,则每个segment上面加锁,进行size计算
        if (check != sum) { // Resort to locking all segments
            sum = 0;
            for (int i = 0; i < segments.length; ++i)
                segments[i].lock();
            for (int i = 0; i < segments.length; ++i)
                sum += segments[i].count;
            for (int i = 0; i < segments.length; ++i)
                segments[i].unlock();
        }
        if (sum > Integer.MAX_VALUE)
            return Integer.MAX_VALUE;
        else
            return (int)sum;
    }
  根据key获取value,put,remove等方法类似,都是调用Segment中相应方法。
public V get(Object key) {
        //计算key的hash值
        int hash = hash(key.hashCode());
 //首先,根据hash值获取指定segment,然后再该segment中获取value的值,获取不到放回null
        return segmentFor(hash).get(key, hash);
    }
  遍历所有的segment,判断是否包含某一个值
 public boolean containsValue(Object value) {
        if (value == null)
            throw new NullPointerException();
        
        final Segment<K,V>[] segments = this.segments;
        int[] mc = new int[segments.length];

        // Try a few times without locking
        for (int k = 0; k < RETRIES_BEFORE_LOCK; ++k) {
            int sum = 0;
            int mcsum = 0;
     //遍历所有的segment,如果包含该value,则返回true
            for (int i = 0; i < segments.length; ++i) {
                int c = segments[i].count;
                mcsum += mc[i] = segments[i].modCount;
                if (segments[i].containsValue(value))
                    return true;
            }
            boolean cleanSweep = true;
            //如果第一次搜寻不包含,判断是否搜寻过程中有对ConcurrentHashMap进行修改,如果有修改,则再进行一次搜寻,如果没有修改,直接返回false
            if (mcsum != 0) {
                for (int i = 0; i < segments.length; ++i) {
                    int c = segments[i].count;
                    if (mc[i] != segments[i].modCount) {
                        cleanSweep = false;
                        break;
                    }
                }
            }
            if (cleanSweep)
                return false;
        }
        // Resort to locking all segments 加锁进行搜索
        for (int i = 0; i < segments.length; ++i)
            segments[i].lock();
        boolean found = false;
        try {
            for (int i = 0; i < segments.length; ++i) {
                if (segments[i].containsValue(value)) {
                    found = true;
                    break;
                }
            }
        } finally {
            for (int i = 0; i < segments.length; ++i)
                segments[i].unlock();
        }
        return found;
    }
  迭代器抽象类:
abstract class HashIterator {
        int nextSegmentIndex;
        int nextTableIndex;
        HashEntry<K,V>[] currentTable;
        HashEntry<K, V> nextEntry;
        HashEntry<K, V> lastReturned;

        HashIterator() {
      //下一个segment,从后往前数
            nextSegmentIndex = segments.length - 1;
            nextTableIndex = -1;
            advance();
        }

        public boolean hasMoreElements() { return hasNext(); }

        final void advance() {
     //如果是链表结构,移动nextEntry指针
            if (nextEntry != null && (nextEntry = nextEntry.next) != null)
                return;
      	    //如果已经到达链表尾部,则nextEntry为table中数组中下一个
            while (nextTableIndex >= 0) {
                if ( (nextEntry = currentTable[nextTableIndex--]) != null)
                    return;
            }
            //找到nextSegmentIndex 、nextTableIndex和nextEntry的位置,从segment最后开始查找起,为什么从最后开始呢?而不是从头?
            while (nextSegmentIndex >= 0) {
                Segment<K,V> seg = segments[nextSegmentIndex--];
                if (seg.count != 0) {
                    currentTable = seg.table;
                    for (int j = currentTable.length - 1; j >= 0; --j) {
                        if ( (nextEntry = currentTable[j]) != null) {
                            nextTableIndex = j - 1;
                            return;
                        }
                    }
                }
            }
        }
  KeySet内部类
//继承与AbstractSet的keySet类,方法都是引用ConcurrentHashMap外的方法
 final class KeySet extends AbstractSet<K> {
        public Iterator<K> iterator() {
            return new KeyIterator();
        }
        public int size() {
            return ConcurrentHashMap.this.size();
        }
        public boolean contains(Object o) {
            return ConcurrentHashMap.this.containsKey(o);
        }
        public boolean remove(Object o) {
            return ConcurrentHashMap.this.remove(o) != null;
        }
        public void clear() {
            ConcurrentHashMap.this.clear();
        }
    }
  Values内部类
//继承于AbstractCollection类,values可以重复,基本上也是调用ConcurrentHashMap方法
final class Values extends AbstractCollection<V> {
        public Iterator<V> iterator() {
            return new ValueIterator();
        }
        public int size() {
            return ConcurrentHashMap.this.size();
        }
        public boolean contains(Object o) {
            return ConcurrentHashMap.this.containsValue(o);
        }
        public void clear() {
            ConcurrentHashMap.this.clear();
        }
    }
 

猜你喜欢

转载自chenghao666.iteye.com/blog/2379214