ConcurrentHashMap基于JDK1.8源码剖析
前言
声明,本文用的是jdk1.8前面章节回顾:
- Collection总览
- List集合就这么简单【源码剖析】
- Map集合、散列表、红黑树介绍
- HashMap就是这么简单【源码剖析】
- LinkedHashMap就这么简单【源码剖析】
- TreeMap就这么简单【源码剖析】
看这篇文章之前最好是有点数据结构的基础:
- Java实现单向链表
- 栈和队列就是这么简单
- 二叉树就这么简单
一、ConCurrentHashMap剖析 ConCurrentHashMap在初学的时候反正我是没有接触过的,不知道你们接触过了没有~
这个类听得也挺少的,在集合中是比较复杂的一个类了,它涉及到了一些多线程的知识点。
不了解或忘记多线程知识点的同学也不要怕,哪儿用到了多线程的知识点,我都会简单介绍一下,并给出对应的资料去阅读的~
好了,我们就来开始吧~
1.1初识ConCurrentHashMap ConCurrentHashMap的底层是:散列表+红黑树,与HashMap是一样的。
文章图片
image 从前面的章节我们也可以发现:最快了解一下类是干嘛的,我们看源码的顶部注释就可以了!
我简单翻译了一下顶部的注释(我英文水平渣,如果有错的地方请多多包涵~欢迎在评论区下指正)
文章图片
2018-04-14_092943.png 根据上面注释我们可以简单总结:
- JDK1.8底层是散列表+红黑树
- ConCurrentHashMap支持高并发的访问和更新,它是线程安全的
- 检索操作不用加锁,get方法是非阻塞的
- key和value都不允许为null
JDK1.7的底层是:segments+HashEntry数组:
文章图片
Xhimkj8.png 图来源:https://blog.csdn.net/panweiwei1994/article/details/78897275
- Segment继承了ReentrantLock,每个片段都有了一个锁,叫做“锁分段”
1.3有了Hashtable为啥需要ConCurrentHashMap
- Hashtable是在每个方法上都加上了Synchronized完成同步,效率低下。
- ConcurrentHashMap通过在部分加锁和利用CAS算法来实现同步。
CAS(比较与交换,Compare and swap) 是一种有名的无锁算法
CAS有3个操作数
- 内存值V
- 旧的预期值A
- 要修改的新值B
- 当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值(A和内存值V相同时,将内存值V修改为B),而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试(否则什么都不做)
接下来我们看看volatile关键字,在初学的时候也很少使用到volatile这个关键字。反正我没用到,而又经常在看Java相关面试题的时候看到它,觉得是一个挺神秘又很难的一个关键字。其实不然,还是挺容易理解的~
volatile经典总结:volatile仅仅用来保证该变量对所有线程的可见性,但不保证原子性
我们将其拆开来解释一下:
- 保证该变量对所有线程的可见性
- 在多线程的环境下:当这个变量修改时,所有的线程都会知道该变量被修改了,也就是所谓的“可见性”
- 不保证原子性
- 修改变量(赋值)实质上是在JVM中分了好几步,而在这几步内(从装载变量到修改),它是不安全的。
- http://www.cnblogs.com/Mainz/p/3556430.html
- https://www.cnblogs.com/Mainz/p/3546347.html
- http://www.dataguru.cn/java-865024-1-1.html
文章图片
rjvoGhc.png 我们来简单看一下他们是什么东东:
文章图片
image 初次阅读完之后,有的属性我也不太清楚它是干什么的,在继续阅读之后可能就明朗了~
1.6ConCurrentHashMap构造方法 ConcurrentHashMap的构造方法有5个:
文章图片
2tXkMrh.png 具体的实现是这样子的:
文章图片
image 可以发现,在构造方法中有几处都调用了
tableSizeFor()
,我们来看一下他是干什么的:点进去之后发现,啊,原来我看过这个方法,在HashMap的时候.....
文章图片
image 它就是用来获取大于参数且最接近2的整次幂的数...
赋值给sizeCtl属性也就说明了:这是下次扩容的大小~
1.7put方法 终于来到了最核心的方法之一:put方法啦~~~~
我们先来整体看一下put方法干了什么事:
文章图片
image 接下来,我们来看看初始化散列表的时候干了什么事:
initTable()
文章图片
NxMQu59.png
- 只让一个线程对散列表进行初始化!
我们可以发现,Node节点是重写的,设置了volatile关键字修饰,致使它每次获取的都是最新设置的值
文章图片
WxQJ58R.png
文章图片
tBI4n51.png 二、总结 上面简单介绍了ConcurrentHashMap的核心知识,还有很多知识点都没有提及到,作者的水平也不能将其弄懂~~有兴趣进入的同学可到下面的链接继续学习。
下面我来简单总结一下ConcurrentHashMap的核心要点:
- 底层结构是散列表(数组+链表)+红黑树,这一点和HashMap是一样的。
- Hashtable是将所有的方法进行同步,效率低下。而ConcurrentHashMap作为一个高并发的容器,它是通过部分锁定+CAS算法来进行实现线程安全的。CAS算法也可以认为是乐观锁的一种~
- 在高并发环境下,统计数据(计算size...等等)其实是无意义的,因为在下一时刻size值就变化了。
- get方法是非阻塞,无锁的。重写Node类,通过volatile修饰next来实现每次获取都是最新设置的值
- ConcurrentHashMap的key和Value都不能为null
- https://blog.csdn.net/u010723709/article/details/48007881
- https://blog.csdn.net/melod_bc/article/details/54150679
- https://blog.csdn.net/panweiwei1994/article/details/78897275
- https://www.jianshu.com/p/e694f1e868ec
文章的目录导航:https://zhongfucheng.bitcron.com/post/shou-ji/wen-zhang-dao-hang
【ConcurrentHashMap基于JDK1.8源码剖析】如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y。为了大家方便,刚新建了一下qq群:742919422,大家也可以去交流交流。谢谢支持了!希望能多介绍给其他有需要的朋友
推荐阅读
- 数据仓库|基于Hive数据仓库的标签画像实战
- 努力学习人工智能|基于图像识别的跌倒检测
- 毕业设计|【毕业设计】基于SSM与VUE的汉服销售论坛系统
- 计算机毕业论文|基于Python的招聘网站爬虫及可视化的设计与实现
- CentOS7基于kubeadm快速搭建Kubernetes集群
- fpga开发|基于FPGA的实时图像边缘检测系统设计(上)
- fpga开发|基于FPGA的实时图像边缘检测系统设计
- 数据库|计算机毕业设计ssm基于b_s架构的实习管理系统
- python|基于MediaPipe的手势识别
- C++ 反调试(基于 SEH 的 SetUnhandledExceptionFilter)