线程安全的集合——ConcurrentHashMap

为什么HashMap集合是线程不安全的?

① 同时put碰撞导致数据丢失:多个线程同时执行put操作,计算出来的hashcode值相等,插入到同一位置导致有的数据被覆盖

② 同时put扩容导致数据丢失:多个线程执行put操作时同时发现需要扩容,也会发生数据丢失

③ 死循环导致CPU100%

ConcurrentHashMap JDK1.7的底层实现
Java 7中的ConcurrentHashMap最外层是多个segment,每个segment的底层数据结构与JDK 1.7的HashMap类似,是基于数组加链表实现的;每个segment独立上ReentrantLock(分段可重入锁),每个segment之间互不影响,提高了并发效率;ConcurrentHashMap默认有16个segment,所以最多可以同时支持16个并发线程写(操作分别分布在不同的segment上),这个默认值可以在初始化的时候设置为其它值,但是一旦初始化之后,是不可以扩容的
在这里插入图片描述
ConcurrentHashMap JDK1.8的底层实现
Java 8中的ConcurrentHashMap是由一个个的节点组成,每个节点的底层数据结构与JDK 1.8的HashMap类似,是基于数组加链表加红黑树实现的
在这里插入图片描述
JDK1.8 putVal 方法的流程: 判断key value不为空(这要与HashMap区分开,HashMap支持key 和 value都为空,ConcurrentHashMap不支持)-> 计算hash值->根据对应位置节点的类型来赋值,或者helpTransfer,或者增长链表,或者给红黑树增加节点->检查满足阀值就转化成红黑树->返回oldVal

JDK1.8 get 方法的流程: 计算hash值->找到对应的位置,分不同情况进行->要么直接取值、要么红黑树找值、要么是链表找值->返回结果

JDK1.7保证线程安全的机制: 使用的是分段锁,也就是为每一个segment加上ReentrantLock锁

JDK1.8保证线程安全的机制: 使用的是CAS机制加上synchronized锁

JDK1.8的HashMap和ConcurrentHashMap为什么设置链表节点超过8就转成红黑树?

因为如果链表节点超过8,那么会导致查询效率非常低,转成红黑树后,复杂度由原来的O(n)转成了O(logn);链表节点超过8的概率是非常小的,一般会出现这种情况最有可能的是哈希算法有问题,为了出现这种情况,才有了转化成红黑树的机制

之所以不一开始就直接使用红黑树来存储,是因为红黑树每个节点占用的地址空间是链表的两倍,为了节省内存空间,一开始采用的是链表存储

扫描二维码关注公众号,回复: 11765274 查看本文章

注意:ConcurrentHashMap的key和value都不能为空

猜你喜欢

转载自blog.csdn.net/can_chen/article/details/108686218
今日推荐