ConcurrentMap

ConcurrentMap 接口下有两个重要的实现ConcurrentHashMap、ConcurrentSkipListMap
 
 ConcurrentSkipListMap这是一个支持高并发度的有序哈希表,并且是无锁的,可在多线程环境下替代TreeMap。支持并发排序功能,弥补ConcurrentHashMap

JDK1.7中的ConcurrentHashMap
底层数据结构分段的数组(Segment)+链表实现
 ConcurrentHashMap 内部使用段(Segment)来表示这些不同的部分,每一个段其实就是一个小的HashTable, 它们有自己的锁。只要多个修改操作发生在不同的段上,它们就可以并发进行。把一个整体分成了16 个段(Segment)。
也就是最高支持16个线程的并发修改操作。 这也是在多线程场景时减小锁粒度从而降低锁竞争的一种方案。并且代码中大多共享变量使用 volatile 关键字声明,目的是第一时间获取修改的内容,性能非常好。
分段锁的思想底层使用的是ReentrantLock,每把锁只锁数组中的一段数据,大大减少锁的竞争
Segment数组中,一个Segment对象就是一把锁,一个Segment对象对应一个HashEntry数组,通过hash值定位HashEntry数组下标
HashEntry中的数据同步依赖于同一把锁,不同HashEntry数组的读写互不干扰。
缺点每次通过hash确认位置的时候,首先需要确认它落在哪个Segment分段,然后在这个分段里再次确认它落在哪个桶里
JDK1.8ConcurrentHashMap
底层数据结构在JDK1.8中,放弃了Segment臃肿的设计,数据结构跟HashMap的数据结构是一样的:数组+红黑树+链表
采用 CAS + Synchronized来保证并发安全进行实现CAS控制数组节点的添加;synchronized只锁定当前链表或红黑二叉树的首节点,只要hash不冲突,就不会产生并发的问题 , 效率得到提升。
常量设置 (这些设置基本和 HashMap 的类似)ConcurrentHashMap 内部是使用一个数组存放数据的, 这个数组的长度必须是 2 的 n 次方, 默认的容量是 16, 最大是 1 << 30, 既 2 的 30 次方
默认负载因子为 0.75, 当数组的的存数据的项 >= 数组的长度 * 负载因子, 就会进行数组长度扩容
数组的每一项, 在 JDK 1.8 中, 可以是链表, 也可以是红黑树。
当数组的长度大于等于 64, 数组的某一项的长度大于等于 8, 会转为红黑树, 小于等于 6, 会重新转为链表
key 和 value 都不允许为 null (HashMap 允许一个 key 为 null 和 不限制的 value 为 null)
在 ConcurrentHash 中数组中的每个节点的 hash 都有特殊作用
总结1. 底层数据结构:
JDK1.7底层采用分段的数组+链表实现
JDK1.8 采用的数据结构跟HashMap1.8的结构一样,数组+链表/红黑二叉树
2. 加锁的方式
JDK1.7采用Segment分段锁,底层使用的是ReentrantLock
JDK1.8采用CAS添加新节点,采用synchronized锁定链表或红黑二叉树的首节点,相对Segment分段锁粒度更细,性能更好


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值