一些简单的理解,细节需要自己看源码
一.数据结构
1.HashMap
数组+链表+红黑树
2.ConcurrentHashMap
数组+链表+红黑树
二.使用场景
1.HashMap
单线程无并发的情况下(多线程会形成环形链表造成死循环)
2.ConcurrentHashMap
多线程有并发的情况下
三.设计角度
1.HashMap
在一个大的集合中快速的取到存储的值
2.ConcurrentHashMap
多线程有并发的情况下在一个大的集合中快速的取到存储的值
四.存储
1.HashMap
1)使用hash算法计算出数据应该存储的位置(数据结构的数组部分也叫位桶)
2)根据计算的结果查看是否有hash冲突来指定存储方式(直接存放/链表/红黑树)
2.ConcurrentHashMap
1)使用hash算法计算出数据应该存储的位置(数据结构的数组部分也叫位桶)
2)根据计算的结果查看是否有hash冲突来指定存储方式(直接存放/链表/红黑树) 这里使用了分段锁
五.扩容
-
HashMap
1)触发条件:
a.当存放数据的数量大于当前map容量的75%(可自定义)时触发扩容(一般有put,putAll的时候触发)
b.数组长度小于64,但是已经要产生红黑树结构(hash碰撞太严重)2)扩容过程
a.扩容至当前容量的两倍(2的整数次幂)
b.遍历数组(位桶)取值,根据数组上面数据的数据结构把数据拿出来,再通过hash算法存放到新的扩容数组里面并赋值给当前map -
ConcurrentHashMap
1)触发条件:
a.当存放数据的数量大于当前map容量的75%(可自定义)时触发扩容(一般有put,putAll的时候触发)
b.数组长度小于64,但是已经要产生红黑树结构(hash碰撞太严重)
c.扩容状态下其他线程对集合进行插入、修改、删除、合并、compute 等操作时遇到 ForwardingNode 节点会触发扩容2)扩容过程
a.扩容至当前容量的两倍(2的整数次幂)
b.根据CPU的核数来决定多线程扩容每条线程需要扩容的大小,如果是单核就线程扩容全部,如果是多线程每条线程最少扩容16个位桶
c.线程扩容的时候标记扩容位(下标),每个线程负责16个,当下标减少为0的时候则扩容完成
d.扩容数据的处理:当位桶数据为链表则根据二进制计算高低位来迁移整个链表;如果是红黑树则拆掉红黑树形成两个链表,一个链表是正常链表,另外一个链表的元素要满足形成红黑树的条件,最终成为一个链表加一个红黑树,再放到新的数组中完成扩容
参考(https://blog.csdn.net/ZOKEKAI/article/details/90051567)