ConcurrentHashMap1.7源码解析

1.前言

ConcurrentHashMap是用Segment分段锁实现的.

2.ConcurrentHashMap属性介绍

类属性

// 默认容量大小
static final int DEFAULT_INITIAL_CAPACITY = 16;
// 默认加载因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;
// 默认并发度
static final int DEFAULT_CONCURRENCY_LEVEL = 16;
// 最大容量
static final int MAXIMUM_CAPACITY = 1 << 30;
// 每段的最小容量
static final int MIN_SEGMENT_TABLE_CAPACITY = 2;
// 最大段数
static final int MAX_SEGMENTS = 1 << 16; 

Segments实例属性

// 哈希桶数组
transient volatile HashEntry<K,V>[] table;
// 当前存储节点个数
transient int count;
// 阈值
transient int threshold;
// 加载因子
final float loadFactor;

3.构造方法

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;
    // 保存ssize是2的几次幂
    int sshift = 0;
    // 用于初始化segments大小
    int ssize = 1;
    // 循环遍历找到大于等于concurrencyLevel的最小2次幂
    while (ssize < concurrencyLevel) {
        ++sshift;
        ssize <<= 1;
    }
    this.segmentShift = 32 - sshift;
    this.segmentMask = ssize - 1;
    if (initialCapacity > MAXIMUM_CAPACITY)
        initialCapacity = MAXIMUM_CAPACITY;
    // 每个segment的容量
    int c = initialCapacity / ssize;
    // 确保总segment容量大于等于initialCapacity
    if (c * ssize < initialCapacity)
        ++c;
    int cap = MIN_SEGMENT_TABLE_CAPACITY;
    while (cap < c)
        cap <<= 1;
    // 初始化index为0的segment,方便后面创建的segment对象可以直接使用这个segment的参数,不需要重复计算
    Segment<K,V> s0 =
        new Segment<K,V>(loadFactor, (int)(cap * loadFactor),
                         (HashEntry<K,V>[])new HashEntry[cap]);
    // 创建segment数组
    Segment<K,V>[] ss = (Segment<K,V>[])new Segment[ssize];
    // 将s0插入到下标index=0上
    UNSAFE.putOrderedObject(ss, SBASE, s0); // ordered write of segments[0]
    this.segments = ss;
}

4.put()

public V put(K key, V value) {
    Segment<K,V> s;
    // value不能为null
    if (value == null)
        throw new NullPointerException();
    // 详见4.1 hash()
    int hash = hash(key);
   	// hash >>> segmentShift 实现与segmentMask的有效位数相同
    int j = (hash >>> segmentShift) & segmentMask;
    // 获取Segmnt[j]的值,如果为空则初始化
    if ((s = (Segment<K,V>)UNSAFE.getObject          
         (segments, (j << SSHIFT) + SBASE)) == null)
         // 详见4.2 ensureSegment()
        s = ensureSegment(j);
    // 详见4.3 put()
    return s.put(key, hash, value, false);
}

4.1 hash()

计算hash值

private int hash(Object k) {
    int h = hashSeed;

    if ((0 != h) && (k instanceof String)) {
        return sun.misc.Hashing.stringHash32((String) k);
    }

    h ^= k.hashCode();

    // 扰动处理
    h += (h <<  15) ^ 0xffffcd7d;
    h ^= (h >>> 10);
    h += (h <<   3);
    h ^= (h >>>  6);
    h += (h <<   2) + (h << 14);
    return h ^ (h >>> 16);
}

4.2 ensureSegment()

private Segment<K,V> ensureSegment(int k) {
    final Segment<K,V>[] ss = this.segments;
    // 根据偏移量计算存储位置
    long u = (k << SSHIFT) + SBASE;
    Segment<K,V> seg;
    if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) == null) { // 当前对应Segment为null
    	// 直接使用Segment[0]的属性来初始化,不需要二次计算
        Segment<K,V> proto = ss[0]; 
        int cap = proto.table.length;
        float lf = proto.loadFactor;
        int threshold = (int)(cap * lf);
        HashEntry<K,V>[] tab = (HashEntry<K,V>[])new HashEntry[cap];
        if ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u))
            == null) { // 双重锁检查
            Segment<K,V> s = new Segment<K,V>(lf, threshold, tab);
            // CAS,自旋锁来设置值
            while ((seg = (Segment<K,V>)UNSAFE.getObjectVolatile(ss, u)) //当前Segment[u]为null则代表还没初始化
                   == null) {
                if (UNSAFE.compareAndSwapObject(ss, u, null, seg = s))
                    break;
            }
        }
    }
    return seg;
}

4.3 Segment.put()

final V put(K key, int hash, V value, boolean onlyIfAbsent) {
	// 如果没有获取到锁,则阻塞在这一步
    HashEntry<K,V> node = tryLock() ? null :
    	// 详见4.4 scanAndLockForPut()
        scanAndLockForPut(key, hash, value);
    // 往下执行,代表已获取到锁
    V oldValue;
    try {
        HashEntry<K,V>[] tab = table;
        int index = (tab.length - 1) & hash;
        // 获取对应在segment中的头节点
        HashEntry<K,V> first = entryAt(tab, index);
        // 循环遍历头节点
        for (HashEntry<K,V> e = first;;) {
            if (e != null) { // 头节点不为null
                K k;
                if ((k = e.key) == key ||
                    (e.hash == hash && key.equals(k))) { // key、hash值相等
                    oldValue = e.value; // 直接覆盖原value值
                    if (!onlyIfAbsent) {
                        e.value = value;
                        ++modCount;
                    }
                    break;
                }
                e = e.next;
            }
            else { // 头节点为null
                if (node != null) // node已初始化
                    node.setNext(first); // 头插法
                else // 初始化node
                    node = new HashEntry<K,V>(hash, key, value, first);
                int c = count + 1;
                if (c > threshold && tab.length < MAXIMUM_CAPACITY) // 判断是否需要扩容
                	// 4.6 rehash()
                    rehash(node);
                else
                	// 直接设置在tab的index上
                    setEntryAt(tab, index, node);
                ++modCount;
                count = c;
                oldValue = null;
                break;
            }
        }
    } finally {
        unlock(); // 释放锁
    }
    return oldValue;
}

4.4 scanAndLockForPut()

private HashEntry<K,V> scanAndLockForPut(K key, int hash, V value) {
	// 4.5 entryForHash(),获取在Segment对应位置的首节点
    HashEntry<K,V> first = entryForHash(this, hash);
    HashEntry<K,V> e = first;
    HashEntry<K,V> node = null;
    int retries = -1;  // 标志位
    while (!tryLock()) { // 尝试加锁
        HashEntry<K,V> f; 
        if (retries < 0) { // 循环遍历e,直到找到key值相等或为null
            if (e == null) { // 当前节点是否为null
                if (node == null) // 初始化node
                    node = new HashEntry<K,V>(hash, key, value, null);
                retries = 0;
            }
            else if (key.equals(e.key)) // key值相等,则设置retries为0
                retries = 0;
            else
                e = e.next;
        }
        else if (++retries > MAX_SCAN_RETRIES) { // 判断重试次数是否大于最大重试次数
        	// 锁住当前Segment
            lock();
            break;
        }
        else if ((retries & 1) == 0 &&
                 (f = entryForHash(this, hash)) != first) { // retries不为1,且重现获取的首节点值与first不相等时
            // 重新进行遍历
            e = first = f;
            retries = -1;
        }
    }
    return node;
}

4.5 entryForHash()

 static final <K,V> HashEntry<K,V> entryForHash(Segment<K,V> seg, int h) {
     HashEntry<K,V>[] tab;
     // 根据hash值获取对应在Segment中的值
     return (seg == null || (tab = seg.table) == null) ? null :
         (HashEntry<K,V>) UNSAFE.getObjectVolatile
         (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE);
 }

4.6 rehash()

private void rehash(HashEntry<K,V> node) {
    HashEntry<K,V>[] oldTable = table;
    int oldCapacity = oldTable.length;
    // 扩容为原容量的两倍
    int newCapacity = oldCapacity << 1;
    threshold = (int)(newCapacity * loadFactor);
    // 新创建一个两倍原容量的table数组
    HashEntry<K,V>[] newTable =
        (HashEntry<K,V>[]) new HashEntry[newCapacity];
    int sizeMask = newCapacity - 1;
    // 遍历原table
    for (int i = 0; i < oldCapacity ; i++) {
        HashEntry<K,V> e = oldTable[i];
        if (e != null) {
            HashEntry<K,V> next = e.next;
            // 计算hash值在新table中的index
            int idx = e.hash & sizeMask;
            if (next == null)   //  当前列表只有个首节点,则直接赋值到newTable的index值上
                newTable[idx] = e;
            else { 
                HashEntry<K,V> lastRun = e;
                int lastIdx = idx;
                for (HashEntry<K,V> last = next;
                     last != null;
                     last = last.next) { // 遍历链表值链表尾节点,找到最后一段相同index的节点
                    int k = last.hash & sizeMask;
                    if (k != lastIdx) {
                        lastIdx = k;
                        lastRun = last;
                    }
                }
                // 直接将找到的最后一段相同节点的首节点赋值
                newTable[lastIdx] = lastRun;
                // 从头节点开始遍历lastRun的前一节点
                for (HashEntry<K,V> p = e; p != lastRun; p = p.next) {
                    V v = p.value;
                    int h = p.hash;
                    int k = h & sizeMask;
                    // 头插法
                    HashEntry<K,V> n = newTable[k];
                    newTable[k] = new HashEntry<K,V>(h, p.key, v, n);
                }
            }
        }
    }
    int nodeIndex = node.hash & sizeMask; // 新增的node节点,使用头插法插入
    node.setNext(newTable[nodeIndex]);
    newTable[nodeIndex] = node;
    table = newTable;
}

5.get()

public V get(Object key) {
    Segment<K,V> s; // manually integrate access methods to reduce overhead
    HashEntry<K,V>[] tab;
    int h = hash(key);
    // 计算对应在Segment数组中的index值
    long u = (((h >>> segmentShift) & segmentMask) << SSHIFT) + SBASE;
    if ((s = (Segment<K,V>)UNSAFE.getObjectVolatile(segments, u)) != null &&
        (tab = s.table) != null) { // 判断对应Segment、segment.table是否为空
        for (HashEntry<K,V> e = (HashEntry<K,V>) UNSAFE.getObjectVolatile
                 (tab, ((long)(((tab.length - 1) & h)) << TSHIFT) + TBASE); // 根据h计算出对应index值,然后遍历table[index]
             e != null; e = e.next) {
            K k;
            if ((k = e.key) == key || (e.hash == h && key.equals(k)))
                return e.value;
        }
    }
    return null;
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值