dtcms 源码 智慧树 datatable bootstrap后台模版 sql视频教程 matlab停止运行命令 mysql错误代码1064 arraylist删除指定元素 mysql自连接 不用u盘装双系统 linux撤销 mysql时间戳转换日期 python指数函数 python时间戳 python正则匹配数字 如何安装java环境 java环境包 java集成开发环境 python源码下载 真实女友补丁 微信签名一句话至自己 linux解压命令 pr抠图 键盘打字手指口诀 轮播图代码 cdr透明度怎么调 vue响应式原理 迅雷共享会员 图片批处理 ppt分节 maya镜像复制 代理服务器软件 繁简体转换 系统重装软件下载 鼠标特效代码 苹果手机哪个版本最好 方正正准黑简体 鼠标点击一下变两下 x怎么关机 广东省电子税务局下载
当前位置: 首页 > 学习教程  > 编程语言

集合之ConcurrentHashMap

2020/12/5 9:40:13 文章标签:

1小时让你了解ConcurrentHashMap ConcurrentHashMap 可以做到既是线程安全的,同时也可以有很高的效率,得益于使用了分段锁。 实现原理 JDK 1.7: ConcurrentHashMap 是通过数组 链表实现,由 Segment 数组和 Segment 元素里对应…

1小时让你了解ConcurrentHashMap

ConcurrentHashMap 可以做到既是线程安全的,同时也可以有很高的效率,得益于使用了分段锁。

实现原理

JDK 1.7:

ConcurrentHashMap 是通过数组 + 链表实现,由 Segment 数组和 Segment 元素里对应多个 HashEntry 组成

value 和链表都是 volatile 修饰,保证可见性

ConcurrentHashMap 采用了分段锁技术,分段指的就是 Segment 数组,其中 Segment 继承于 ReentrantLock

理论上 ConcurrentHashMap 支持 CurrencyLevel (Segment 数组数量)的线程并发,每当一个线程占用锁访问一个 Segment 时,不会影响到其他的 Segment

put 方法的逻辑较复杂:

尝试加锁,加锁失败 scanAndLockForPut 方法自旋,超过 MAX_SCAN_RETRIES 次数,改为阻塞锁获取

将当前 Segment 中的 table 通过 key 的 hashcode 定位到 HashEntry

遍历该 HashEntry,如果不为空则判断传入的 key 和当前遍历的 key 是否相等,相等则覆盖旧的 value

不为空则需要新建一个 HashEntry 并加入到 Segment 中,同时会先判断是否需要扩容

最后释放所获取当前 Segment 的锁

get 方法较简单:

将 key 通过 hash 之后定位到具体的 Segment,再通过一次 hash 定位到具体的元素上

由于 HashEntry 中的 value 属性是用 volatile 关键词修饰的,保证了其内存可见性

JDK 1.8:

抛弃了原有的 Segment 分段锁,采用了 CAS + synchronized 来保证并发安全性

HashEntry 改为 Node,作用相同

val next 都用了 volatile 修饰

put 方法逻辑:

根据 key 计算出 hash 值

判断是否需要进行初始化

根据 key 定位出的 Node,如果为空表示当前位置可以写入数据,利用 CAS 尝试写入,失败则自旋

如果当前位置的 hashcode == MOVED == -1,则需要扩容

如果都不满足,则利用 synchronized 锁写入数据

如果数量大于 TREEIFY_THRESHOLD 则转换为红黑树

get 方法逻辑:

根据计算出来的 hash 值寻址,如果在桶上直接返回值

如果是红黑树,按照树的方式获取值

如果是链表,按链表的方式遍历获取值

JDK 1.7 到 JDK 1.8 中的 ConcurrentHashMap 最大的改动:

链表上的 Node 超过 8 个改为红黑树,查询复杂度 O(logn)

ReentrantLock 显示锁改为 synchronized,说明 JDK 1.8 中 synchronized 锁性能赶上或超过 ReentrantLock


本文链接: http://www.dtmao.cc/news_show_450052.shtml

附件下载

上一篇:JDK代理模式

下一篇:如何使用多配置yml

相关教程

    暂无相关的数据...

共有条评论 网友评论

验证码: 看不清楚?