小垃圾学Java-ConcurrentHashMap

jdk1.7源码下

ConcurrentHashMap的介绍

AbstractMap类继承了Map接口,也就是说存放着键值对,还有实现了Map接口那些方法。
在这里插入图片描述
通过“分段锁”来实现多线程下的安全问题。它将哈希表分成了不同的段内使用了可重入锁(ReentrantLock ),不同线程只在一个段内存在线程的竞争。它不会对整个哈希表加锁。

ConcurrentHashMap底层数据结构

ConcurrentHashMap中的分段锁称为Segment,它即类似于HashMap的结构。它内部拥有一个HashEntry数组,数组中的每个元素又是一个链表;同时又是一个ReentrantLock(Segment继承了ReentrantLock)
ConcurrentHashMap有数组segment,segment有数组hashentry ,然后通过链表链接
如图所示:
在这里插入图片描述
Segment继承了可重入锁
在这里插入图片描述
HashEntry这个类有key、value、next、hash四个属性。HashEntry中的value被volatile修饰,这样在多线程读写过程中能够保持它们的可见性
在这里插入图片描述

HashMap、HashTable和ConcurrentHashMap区别是什么?

1.ConcurrentHashMap 、HashTable不允许值为null,值为null时抛出异常,HashMap允许值为null
2. HashTable所有方法都加锁synchronized,为线程安全的。HashMap不保证线程安全。ConcurrentHashMap采用了分段锁,在迭代的过程中,ConcurrentHashMap仅仅锁定map的某个部分,而Hashtable则会锁定整个map。
3. ConcurrentHashMap为弱一致性,在get方法时有可能获得过时的数据。

在jdk1.7和1.8中的区别

数据结构的不同

1.7是对segment实行分段所 和自旋锁–数组+链表。
1.8是对实行了abs和syn原子操作—数组+链表+红黑树-- 优先红黑树

put、get方法

jdk1.7中

虽然 HashEntry 中的 value 是用 volatile 关键词修饰的,但是并不能保证并发的原子性,所以 put 操作时仍然需要加锁处理。
首先第一步的时候会尝试获取锁,如果获取失败肯定就有其他线程存在竞争,则利用 scanAndLockForPut() 自旋获取锁。在这里插入图片描述

put的流程:

1.将当前 Segment 中的 table 通过 key 的 hashcode 定位到 HashEntry。
2.遍历该 HashEntry,如果不为空则判断传入的 key 和当前遍历的 key 是否相等,相等则覆盖旧的 value。
3.不为空则需要新建一个 HashEntry 并加入到 Segment 中,同时会先判断是否需要扩容。
4.最后会解除在 1 中所获取当前 Segment 的锁。

get的流程:

只需要将 Key 通过 Hash 之后定位到具体的 Segment ,再通过一次 Hash 定位到具体的元素上。
由于 HashEntry 中的 value 属性是用 volatile 关键词修饰的,保证了内存可见性,所以每次获取时都是最新值。
ConcurrentHashMap 的 get 方法是非常高效的,因为整个过程都不需要加锁。

jdk1.8中:

抛弃了原有的 Segment 分段锁,而采用了 CAS + synchronized 来保证并发安全性
将 1.7 中存放数据的 HashEntry 改为 Node,但作用都是相同的。
在这里插入图片描述

put的流程:

在这里插入图片描述

  • 根据 key 计算出 hashcode 。
  • 判断是否需要进行初始化。
  • f 即为当前 key 定位出的Node,如果为空表示当前位置可以写入数据,利用 CAS 尝试写入,失败则自旋保证成功。
  • 如果当前位置的 hashcode =MOVED=-1,则需要进行扩容。
  • 如果都不满足,则利用 synchronized 锁写入数据。
  • 如果数量大于 TREEIFY_THRESHOLD 则要转换为红黑树。

get的流程:
在这里插入图片描述

  • 根据计算出来的 hashcode 寻址,如果就在桶上那么直接返回值。
  • 如果是红黑树那就按照树的方式获取值。
  • 就不满足那就按照链表的方式遍历获取值。
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值