前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >一文读懂JAVA并发容器类ConcurrentHashMap

一文读懂JAVA并发容器类ConcurrentHashMap

作者头像
IT架构圈
发布2020-10-10 10:59:17
6780
发布2020-10-10 10:59:17
举报
文章被收录于专栏:IT架构圈

上文说了HashMap,其实HashMap是线程非安全的,JDK里面有个线程安全的就是HashTable,查看HashTable每个方法都增加了synchronized同步锁,也就说每次只能进入一个线程,这样影响效率。JDK源码也推荐使用ConcurrentHashMap。

推理ConcurrentHashMap的实现1.8
  • ① JDK的描述
代码语言:javascript
复制
If a thread-safe implementation is not needed, it is recommended to use HashMap in place of code Hashtable. If a thread-safe highly-concurrent implementation is desired, then it is recommended to use ConcurrentHashMap in place of code Hashtable.

如果你不需要线程安全,那么使用HashMap,如果需要线程安全,那么使用ConcurrentHashMap。HashTable已经被淘汰了,不要在新的代码中再使用它。

  • ② 描述

和 HashMap 非常类似,唯一的区别就是其中的核心数据如 value ,以及链表都是 volatile 修饰的,保证了获取时的可见性。原理上来说:根据 key 计算出 hashcode ,判断是否需要进行初始化,f 即为当前 key 定位出的 Node,如果为空表示当前位置可以写入数据,利用 CAS 尝试写入,多个线程操作只有一个成功,失败则自旋保证成功。如果当前位置的 hashcode == MOVED == -1,则需要进行扩容。如果都不满足,则利用 synchronized 锁写入数据。,如果数量大于 TREEIFY_THRESHOLD 则要转换为红黑树。。Mysql里面有表锁和行锁的概念。表锁就是HashTable,行锁就是ConcurrentHashMap 。

  • ③ JDK1.8中的ConcurrentHashMap原理分析

1.7 已经解决了并发问题,并且能支持 N 个 Segment 这么多次数的并发,但依然存在 HashMap 在 1.7 版本中的问题。那么是什么问题呢?很明显那就是查询遍历链表效率太低。

因此 1.8 做了一些数据结构上的调整。,在 JAVA8 中它摒弃了 Segment(锁段)的概念,而是启用了一种全新的方式实现,利用 CAS 算法。底层依然由“数组”+链表+红黑树的方式思想,但是为了做到并发,又增加了很多辅助的类,例如 TreeBin、Traverser等对象内部类。如何让多线程之间,对象的状态对于各线程的“可视性”是顺序一致的:ConcurrentHashMap 使用了 happensbefore 规则来实现。happens-before规则(摘取自 JAVA 并发编程):

程序次序法则

线程中的每个动作A都 happens-before 于该线程中的每一个动作B,其中,在程序中,所有的动作B都能出现在A之后。

监视器锁法则

对一个监视器锁的解锁 happens-before 于每一个后续对同一监视器锁的加锁。

volatile 变量法则

对 volatile 域的写入操作 happens-before 于每一个后续对同一个域的读写操作。

线程启动法则

在一个线程里,对 Thread.start 的调用会 happens-before 于每个启动线程的动作。

线程终结法则

线程中的任何动作都 happens-before 于其他线程检测到这个线程已经终结、或者从 Thread.join 调用中成功返回,或 Thread.isAlive 返回 false。

中断法则

一个线程调用另一个线程的 interrupt happens-before 于被中断的线程发现中断。

终结法则

一个对象的构造函数的结束 happens-before 于这个对象 finalizer 的开始。

传递性

如果 A happens-before 于 B,且 B happens-before 于 C,则 A happens-before于C: 假设代码有两条语句,代码顺序是语句1先于语句2执行;那么只要语句之间不存在依赖关系,那么打乱它们的顺序对最终的结果没有影响的话,那么真正交给CPU去执行时,他们的执行顺序可以是先执行语句2然后语句1。

PS:不管是1.7的hashMap还是ConcurrentHashMap,源码的可读性变差。目前基本都是jdk1.8就没有说1.7的事情,毕竟事务都是在进化的。里面用到了很多数据结构,数据结构说难也不难,说容易也不容易,它本身就是人的思维的一种体现。好像说走路方式一样,怎么走都可以到指定的地方,但是方法不一样,数据结构就是通过更加科学方式来进行,归根到底还是看我的【数据结构与算法】专题。数据结构给你,通过算法来进行查找,如果是遍历的方式来查,可能相对于hash的形式要差一些。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2020-09-25,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 编程坑太多 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 推理ConcurrentHashMap的实现1.8
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档