参考链接:【十四】Java集合之ConcurrentHashMap源码分析(1.8)_courrenthashmap1.8每个数组都有一个-CSDN博客
添加几个链接有1.7和1.8的源码:
1.7:
1.8的源码:
【多线程】ConcurrentHashMap1.8源码保姆级解析_concurrenthashmap源码分析1.8-CSDN博客
总括:数组+链表+红黑树。
为什么要用红黑树呢?因为在hash冲突严重的情况下,链化严重会导致查询效率变为O(n)。所以,引入红黑树。当链表长度大于8,数组长度大于64时,会树化。以空间换时间,查询效率变为O(nLognN)。
使用CAS+synchronized+volatile来保证并发安全。保证线程安全一定要保证:原子性,可见性,有序性。
内部类:
1.Node
这是Node的基类,也是其他Node的基类。整个table的结构就是Node数组,用volatile保证value和netNode在被修改时的可见性和有序性。
2.TreeNode
红黑树Node,继承自Node。成员:父节点,左孩子节点,右孩子节点,前一个节点,颜色。
put元素时,使用CAS保证原子性。(根据数组长度减1再对hash值取余得到在Node数组中位于哪个下标,用tabAt获取数组中该下标的元素)。
如果链表长度>8,将链表转为红黑树(而这个方法中会判断数组值是否大于64,如果没有大于64,则只扩容)。
如果是第一个扩容的就开始,如果有别的线程在 扩容就帮助别的线程一起扩容。
扩容是怎样保证线程安全的?
比如:现在的数组长度为32,线程A迁移0-15的桶,线程B迁移16-31的桶。当前哪些区间的桶被分配的临界值用一个变量表示,对他的修改是CAS的,所以多线程扩容安全。