看ConcurrentHashMap的,一般都看过HashMap的了,那么我们就直奔主题吧。
> 参考的优秀文章
Java集合---ConcurrentHashMap原理分析
> 构造方法
/** * The default concurrency level for this table, used when not * otherwise specified in a constructor. */ static final int DEFAULT_CONCURRENCY_LEVEL = 16; ...... public ConcurrentHashMap(int initialCapacity, float loadFactor, int concurrencyLevel)
直接来到这个构造方法,可以看到,默认的concurrencyLevel为16,可以理解为分16个segment,操作时以segment为粒度大小加锁。
在HashMap基础上增加了:
1、计算segmentShift、segmentMask(用途下面会提到)
2、计算cap,实例化ss(segment的数组)、s0(第一个segment)(用途下面会提到)
int sshift = 0; int ssize = 1; while (ssize < concurrencyLevel) { ++sshift; ssize <<= 1; } this.segmentShift = 32 - sshift; this.segmentMask = ssize - 1;
这段代码为了计算segmentShift(如需加入某元素,将它分配到某个segment需移动的位数)、segmentMask(此掩码用于计算分配到哪个segment)
concurrencyLevel可以看为分多少个segment,即segment[]的长度
segmentMask这个掩码后面被用来跟hash值的高位做&操作,从而确定分配到哪个segment;
sshift为segmentMask二进制的位数,用来求segmentShift;
而segmentShift后面用来为hash值右移的位数,从而获取hash的高多少位来做&运算。
这段代码简单打印各个值,便于理解:
public class SegmentShiftMask { public static void main(String[] args) { for (int i = 1; i < 20; i++) { test(i); } } public static void test(int concurrencyLevel) { int sshift = 0; int ssize = 1; while (ssize < concurrencyLevel) { ++sshift; ssize <<= 1; } int segmentShift = 32 - sshift; int segmentMask = ssize - 1; System.out.println("concurrencyLevel : " + concurrencyLevel + " \t= " + String.format("%08d", Integer.valueOf(Integer.toBinaryString(concurrencyLevel)))); System.out.println("sshift : " + sshift); System.out.println("segmentShift : " + segmentShift); System.out.println("segmentMask : " + segmentMask + " \t= " + String.format("%08d", Integer.valueOf(Integer.toBinaryString(segmentMask)))); System.out.println("--------"); } }