ConcurrentHashMap(JDK8)源码分析及夺命9连问

ConcurrentHashMap(jdk1.8)

底层操作

 //数组对象 = 头对象(8bytes) + 指针对象(4bytes) + 数组长度(4bytes) + 数据(xxxbytes)
Class<?> ak = Node[].class;             //Node[]Class 对象ak
ABASE = U.arrayBaseOffset(ak);          //头对象 + 指针对象 + 数组对象 = 16
int scale = U.arrayIndexScale(ak);      //单个元素的大小  int(4bytes) long(8bytes)
if ((scale & (scale - 1)) != 0)   //scale必须是2的幂
    throw new Error("data type scale not a power of two");

/**
	Integer.numberOfLeadingZeros(n)  计算n的二进制从最高有效位往左有几个0  
		案例: n = 4   二进制 100    32-3=29   
			  ASHIFT = 31-29 = 2
**/
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale); 



/**
	该方法的目的: 取出table[i]
	
	(i << ASHIFT) + ABASE   i是角标    
		接着上面的案例:   i* 4 + 16    
		相当于数组的寻址公式 a[i]_address = data_type_size*i + base_adress
**/
static final <K,V> Node<K,V> tabAt(Node<K,V>[] tab, int i) {
    return (Node<K,V>)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
}


/**
	该方法的目的: CAS操作  更新值为v   table[i] = v
	((long)i << ASHIFT) + ABASE 这个上面说了就是寻址公式能够找到该元素 在底层所在的位置
**/
static final <K,V> boolean casTabAt(Node<K,V>[] tab, int i,
                                    Node<K,V> c, Node<K,V> v) {
    return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
}

一、 容器初始化

1.源码分析

public ConcurrentHashMap() {
}
public ConcurrentHashMap(int initialCapacity) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException();
    int cap = ((initialCapacity >= (MAXIMUM_CAPACITY >>> 1)) ?
               MAXIMUM_CAPACITY :
               tableSizeFor(initialCapacity + (initialCapacity >>> 1) + 1));
    this.sizeCtl = cap;
}
//基于一个Map集合,构建一个ConcurrentHashMap
//初始容量为16
public ConcurrentHashMap(Map<? extends K, ? extends V> m) {
    this.sizeCtl = DEFAULT_CAPACITY;
    putAll(m);
}

2.sizeCtl含义解释

注意: 以上这些构造方法中都涉及到一个变量sizeCtl,这个变量是一个非常重要的变量。
而且具有非常丰富的含义,它的值不同,对应的含义也不一样,这里先做一些简单说明:

sizeCtl 为0, 代表数组未初始化,且数组的初始容量为16

sizeCtl 为正数,如果数组未初始化,那么其记录的是数组的初始容量,如果数组已经初始化,那么其记录的是数组的扩容阈值 (数组的初始容量*0.75 sc = n - (n >>> 2)

上一篇:JDK8中接口的新特性


下一篇:Windows系统和Linux系统安装JDK8详细教程