1
public ConcurrentHashMap(int initialCapacity,
 float loadFactor, int concurrencyLevel) {
        int sshift = 0;
        int ssize = 1;
        //找到一个大于或等于concurrencyLevel 的一个
        //2的幂次方数
        while (ssize < concurrencyLevel) {
            ++sshift;
            ssize <<= 1;
        }
        //后面用于取hashcode的高位进行运算
        this.segmentShift = 32 - sshift;
        this.segmentMask = ssize - 1;
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        //确定HahsEntry数组的长度
        int c = initialCapacity / ssize;
        //上面除可能造成了“向下取整”,而这里要“向上取整”
        //所以进行以下判断进行+1
        if (c * ssize < initialCapacity)
            ++c;
        //MIN_SEGMENT_TABLE_CAPACITY 默认为2,
        //即HashEntry数组最小长度为2
        int cap = MIN_SEGMENT_TABLE_CAPACITY;
        //这里同样是找一个大于等于c的一个2的幂次方数
        //cap就是HashEntry对象的容量
        while (cap < c)
            cap <<= 1;
        // create segments and segments[0]
        //创建一个Segment s0对象存放在Segment数组下标为0的
        //位置,便于后面存放元素不用再重新计算HahsEntry
        //的容量等属性(原型设计思想)
        Segment<K,V> s0 =
            new Segment<K,V>(loadFactor, (int)(cap * loadFactor),
                             (HashEntry<K,V>[])new HashEntry[cap]);
        Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize];
        //将s0写入ss数组地址为SBASE的位置(就是下标为0)
        UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]
        this.segments = ss;
    }
    public V put(K key, V value) {
        Segment<K,V> s;
        //这里说明jdk7的ConcurentHashMap是不能存放空的
        if (value == null)
            throw new NullPointerException();
        //算hashcode 这里基本跟jdk7中HashMap 
        //hash方法一样
        int hash = hash(key);
        //这里hash值取高位 & segmentMask(即Segment数组的长度,最后求出存放的对应Segment数组下标的位置)
        int j = (hash >>> segmentShift) & segmentMask;
        //这里可以理解为取Segment数组第j位置上的值,
        //如果为空则调用 ensureSegment(j) 方法
        if ((s = (Segment<K,V>)UNSAFE.getObject          // nonvolatile; recheck
             (segments, (j << SSHIFT) + SBASE)) == null) //  in ensureSegment
             //该方法用于返回一个Segment对象,后面具体分析
            s = ensureSegment(j);
        return s.put(key, hash, value, false);
    }
ensureSegment方法分析
    private Segment<K,V> ensureSegment(int k) {
        final Segment<K,V>[] ss = this.segments;
        //获取存放当前元素在Segment数组下标的位置
        long u = (k << SSHIFT) + SBASE; // raw offset
        Segment<K,V> seg;
        //如果获取Segment数组下标为u的元素,如果为空则取
        //ss[0]位置上的元素,获取对应HashEntry的属性,便于
        //创建一个HashEntry对象
        if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) {
            Segment<K,V> proto = ss[0]; // use segment 0 as prototype
            //默认HashEntry数组大小
            int cap = proto.table.length;
            //默认加载因子
            float lf = proto.loadFactor;
            //存放元素个数上极限
            int threshold = (int)(cap * lf);
            //创建一个HashEntry对象
            HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry[cap];
            //再次检查下标为u的位置是否为空,可能并发操作
            //有元素进来并创建好了
            if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
                == null) { // recheck
                Segment<K,V> s = new Segment<K,V>(lf, threshold, tab);
            //如果为空则利用cas防止并发,将创建好的Segment对象放入下标为u的位置,即只可能有一个线程成功
                while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
                       == null) {
                    if (UNSAFE.compareAndSwapObject(ss, u, null, seg = s))
                        break;
                }
            }
        }
        return seg;
    }
s.put(key, hash, value, false)方法解析
/**
*key : 存放元素的key
*hash : key对应的hash值
*value : 存放的value
* onlyIfAbsent : 存在相同的key 是否覆盖原值
*/
final V put(K key, int hash, V value, boolean onlyIfAbsent) {
            HashEntry<K,V> node = tryLock() ? null :
                scanAndLockForPut(key, hash, value);
            V oldValue;
            try {
                HashEntry<K,V>[] tab = table;
                int index = (tab.length - 1) & hash;
                HashEntry<K,V> first = entryAt(tab, index);
                for (HashEntry<K,V> e = first;;) {
                    if (e != null) {
                        K k;
                        if ((k = e.key) == key ||
                            (e.hash == hash && key.equals(k))) {
                            oldValue = e.value;
                            if (!onlyIfAbsent) {
                                e.value = value;
                                ++modCount;
                            }
                            break;
                        }
                        e = e.next;
                    }
                    else {
                        if (node != null)
                            node.setNext(first);
                        else
                            node = new HashEntry<K,V>(hash, key, value, first);
                        int c = count + 1;
                        if (c > threshold && tab.length < MAXIMUM_CAPACITY)
                            rehash(node);
                        else
                            setEntryAt(tab, index, node);
                        ++modCount;
                        count = c;
                        oldValue = null;
                        break;
                    }
                }
            } finally {
                unlock();
            }
            return oldValue;
        }

大老板
4 声望0 粉丝

« 上一篇
JDK7HashMap