在阅读源码的过程中,推荐一个idea的翻译插件TranslationPlugin,方便阅读源码的注释。本篇主要介绍ConcurrentHashMap在JDK1.8中的实现。
ConcurrentHashMap静态常量
ConcurrentHashMap在设计的过程中涉及到扩容和容器收缩等策略,在静态常量中定义了一些比较关键的阈值,这里介绍几个主要的:
private static final int DEFAULT_CAPACITY=16,默认表大小,默认初始化的时候没有传递capacity和concurrentlevel会提供16个hash桶进行映射。否则会根据capacity或者concurrentlevel来确定size的值。
private static final int MAXIMUM_CAPACITY = 1 << 30,最大表容量,扩容时会判断最大容量。
static final int MIN_TREEIFY_CAPACITY = 64,链表树化时的最小表(数组)容量。在列表树化的时候会检测当前的表(数组)容量,如果小于这个数值会首先进行扩容,扩容之后再进行树化。n为表(数组)长度。
1
2if ((n = tab.length) < MIN_TREEIFY_CAPACITY)
tryPresize(n << 1);private static final float LOAD_FACTOR = 0.75f,装载因子,当数组中已经映射的hash桶已经达到百分之75以上时会自动扩容。代码中可以用 {@code n - (n >>> 2)}代替运算,n为表(数组)的长度。
static final int TREEIFY_THRESHOLD = 8,链表调整为tree阈值。当链表中的节点数量超过这个数值的时候会调整为树结构。这个数量至少为2最好是大于8。
static final int UNTREEIFY_THRESHOLD = 6,当链表的长度小于这个值的时候自动调节树结构为列表结构。
方法解析
分析一下数组的扩容方法tryPresize,源代码如下:
1 | /** |
再看一下主要的putVal方法,源代码如下:
1 | /** Implementation for put and putIfAbsent */ |
总结
从ConcurrentHashMap的多个版本演变中,最终java9采用了synchronized和cas来实现,之后会抽写一篇对几种版本迭代过程中性能的优异比较。