前言

声明,本文用的是jdk1.8

前面章节回顾:

本篇主要讲解ConCurrentHashMap~

看这篇文章之前最好是有点数据结构的基础:

当然了,如果讲得有错的地方还请大家多多包涵并不吝在评论去指正~

一、ConCurrentHashMap剖析

ConCurrentHashMap在初学的时候反正我是没有接触过的,不知道你们接触过了没有~

这个类听得也挺少的,在集合中是比较复杂的一个类了,它涉及到了一些多线程的知识点。

不了解或忘记多线程知识点的同学也不要怕,哪儿用到了多线程的知识点,我都会简单介绍一下,并给出对应的资料去阅读的~

好了,我们就来开始吧~

1.1初识ConCurrentHashMap

ConCurrentHashMap的底层是:散列表+红黑树,与HashMap是一样的。

从前面的章节我们也可以发现:最快了解一下类是干嘛的,我们看源码的顶部注释就可以了!

我简单翻译了一下顶部的注释(我英文水平渣,如果有错的地方请多多包涵~欢迎在评论区下指正)

根据上面注释我们可以简单总结:

  • JDK1.8底层是散列表+红黑树
  • ConCurrentHashMap支持高并发的访问和更新,它是线程安全
  • 检索操作不用加锁,get方法是非阻塞的
  • key和value都不允许为null

1.2JDK1.7底层实现

上面指明的是JDK1.8底层是:散列表+红黑树,也就意味着,JDK1.7的底层跟JDK1.8是不同的~

JDK1.7的底层是:segments+HashEntry数组:

图来源:https://blog.csdn.net/panweiwei1994/article/details/78897275

  • Segment继承了ReentrantLock,每个片段都有了一个锁,叫做“锁分段

大概了解一下即可~

1.3有了Hashtable为啥需要ConCurrentHashMap

  • Hashtable是在每个方法上都加上了Synchronized完成同步,效率低下。
  • ConcurrentHashMap通过在部分加锁利用CAS算法来实现同步。

1.4CAS算法和volatile简单介绍

在看ConCurrentHashMap源码之前,我们来简单讲讲CAS算法和volatile关键字

CAS(比较与交换,Compare and swap) 是一种有名的无锁算法

CAS有3个操作数

  • 内存值V
  • 旧的预期值A
  • 要修改的新值B

当且仅当预期值A和内存值V相同时,将内存值V修改为B,否则什么都不做

  • 当多个线程尝试使用CAS同时更新同一个变量时,只有其中一个线程能更新变量的值(A和内存值V相同时,将内存值V修改为B),而其它线程都失败,失败的线程并不会被挂起,而是被告知这次竞争中失败,并可以再次尝试(否则什么都不做)

看了上面的描述应该就很容易理解了,先比较是否相等,如果相等则替换(CAS算法)


接下来我们看看volatile关键字,在初学的时候也很少使用到volatile这个关键字。反正我没用到,而又经常在看Java相关面试题的时候看到它,觉得是一个挺神秘又很难的一个关键字。其实不然,还是挺容易理解的~

volatile经典总结:volatile仅仅用来保证该变量对所有线程的可见性,但不保证原子性

我们将其拆开来解释一下:

  • 保证该变量对所有线程的可见性

    • 在多线程的环境下:当这个变量修改时,所有的线程都会知道该变量被修改了,也就是所谓的“可见性”
  • 不保证原子性
    • 修改变量(赋值)实质上是在JVM中分了好几步,而在这几步内(从装载变量到修改),它是不安全的

如果没看懂或者想要深入了解其原理和可参考下列博文:

1.5ConCurrentHashMap域

域对象有这么几个:

我们来简单看一下他们是什么东东:

初次阅读完之后,有的属性我也不太清楚它是干什么的,在继续阅读之后可能就明朗了~

1.6ConCurrentHashMap构造方法

ConcurrentHashMap的构造方法有5个:

具体的实现是这样子的:

可以发现,在构造方法中有几处都调用了tableSizeFor(),我们来看一下他是干什么的:

点进去之后发现,啊,原来我看过这个方法,在HashMap的时候.....

它就是用来获取大于参数且最接近2的整次幂的数...

赋值给sizeCtl属性也就说明了:这是下次扩容的大小~

1.7put方法

终于来到了最核心的方法之一:put方法啦~~~~

我们先来整体看一下put方法干了什么事:

接下来,我们来看看初始化散列表的时候干了什么事:initTable()

  • 只让一个线程对散列表进行初始化

1.8get方法

从顶部注释我们可以读到,get方法是不用加锁的,是非阻塞的。

我们可以发现,Node节点是重写的,设置了volatile关键字修饰,致使它每次获取的都是最新设置的值

二、总结

上面简单介绍了ConcurrentHashMap的核心知识,还有很多知识点都没有提及到,作者的水平也不能将其弄懂~~有兴趣进入的同学可到下面的链接继续学习。

下面我来简单总结一下ConcurrentHashMap的核心要点:

  • 底层结构是散列表(数组+链表)+红黑树,这一点和HashMap是一样的。
  • Hashtable是将所有的方法进行同步,效率低下。而ConcurrentHashMap作为一个高并发的容器,它是通过部分锁定+CAS算法来进行实现线程安全的。CAS算法也可以认为是乐观锁的一种~
  • 在高并发环境下,统计数据(计算size...等等)其实是无意义的,因为在下一时刻size值就变化了。
  • get方法是非阻塞,无锁的。重写Node类,通过volatile修饰next来实现每次获取都是最新设置的值
  • ConcurrentHashMap的key和Value都不能为null

参考资料:


明天要是无意外的话,可能会写Set集合,敬请期待哦~~~~

文章的目录导航https://zhongfucheng.bitcron.com/post/shou-ji/wen-zhang-dao-hang

如果文章有错的地方欢迎指正,大家互相交流。习惯在微信看技术文章,想要获取更多的Java资源的同学,可以关注微信公众号:Java3y。为了大家方便,刚新建了一下qq群:742919422,大家也可以去交流交流。谢谢支持了!希望能多介绍给其他有需要的朋友

ConcurrentHashMap基于JDK1.8源码剖析的更多相关文章

  1. ConCurrentHashMap(基于jdk1.8源码)(转载来源https://segmentfault.com/a/1190000014380257)

    ConCurrentHashMap的底层是:散列表+红黑树,与HashMap是一样的.(不允许key和value是null值) JDK1.8底层是散列表+红黑树 ConCurrentHashMap支持 ...

  2. HashMap(JDK1.8)源码剖析

    在JDK1.6中,HashMap采用位桶+链表实现,即使用链表处理冲突,同一hash值的Entity都存储在一个链表里.但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找 ...

  3. Python 源码剖析(一)【python对象】

    处于研究python内存释放问题,在阅读部分python源码,顺便记录下所得.(基于<python源码剖析>(v2.4.1)与 python源码(v2.7.6)) 先列下总结:      ...

  4. 基于mybatis-generator-core 1.3.5项目的修订版以及源码剖析

    项目简单说明 mybatis-generator,是根据数据库表.字段反向生成实体类等代码文件.我在国庆时候,没事剖析了mybatis-generator-core源码,写了相当详细的中文注释,可以去 ...

  5. 转:【Java集合源码剖析】Hashtable源码剖析

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/36191279 Hashtable简介 Hashtable同样是基于哈希表实现的,同样每个元 ...

  6. 转:【Java集合源码剖析】HashMap源码剖析

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/36034955   您好,我正在参加CSDN博文大赛,如果您喜欢我的文章,希望您能帮我投一票 ...

  7. 转:【Java集合源码剖析】Vector源码剖析

    转载请注明出处:http://blog.csdn.net/ns_code/article/details/35793865   Vector简介 Vector也是基于数组实现的,是一个动态数组,其容量 ...

  8. ThreadLocal终极源码剖析

    目录一.ThreadLocal1.1 源码注释1.2 源码剖析      散列算法-魔数0x61c88647      set操作    get操作    remove操作1.3 功能测试1.4 应用 ...

  9. HashMap就是这么简单【源码剖析】

    前言 声明,本文用得是jdk1.8 前面已经讲了Collection的总览和剖析List集合以及散列表.Map集合.红黑树的基础了: Collection总览 List集合就这么简单[源码剖析] Ma ...

随机推荐

  1. Redis主从集群的Sentinel配置

    http://www.cnblogs.com/LiZhiW/p/4851631.html

  2. c++ --> extern "C" {}详解

    extern "C" {}详解 extern "C"的真实目的是实现类C和C++的混合编程.在C++源文件中的语句前面加上extern "C" ...

  3. 动态规划(Dynamic programming) 走楼梯

    来自:算法爱好者 有一座高度是10级台阶的楼梯,从下往上走,每跨一步只能向上1级或者2级台阶,要求用程序来求出一共有多少种走法? f(10) = f(9) + f(8) f(9) = f(8) + f ...

  4. Jmeter-基于Ubuntu运行

    这几天折腾了很久,整合了一套接口自动化的持续集成工具,先从最基础的运行Jmeter说起.由于我是用Docker部署的持续集成环境,所以接口运行必须在服务器上 一:在Linux服务器先安装jdk 1:先 ...

  5. 记录python接口自动化测试--利用unittest生成测试报告(第四目)

    前面介绍了是用unittest管理测试用例,这次看看如何生成html格式的测试报告 生成html格式的测试报告需要用到 HTMLTestRunner,在网上下载了一个HTMLTestRunner.py ...

  6. 2017-2018-1 20155214&20155216 实验四:外设驱动程序设计

    2017-2018-1 20155214&20155216 实验四:外设驱动程序设计 实验四外设驱动程序设计-1 实验要求: 学习资源中全课中的"hqyj.嵌入式Linux应用程序开 ...

  7. 标准C++类std::string的内存共享和Copy-On-Write(写时拷贝)

    标准C++类std::string的内存共享,值得体会: 详见大牛:https://www.douban.com/group/topic/19621165/ 顾名思义,内存共享,就是两个乃至更多的对象 ...

  8. OO第一次阶段性总结

    经过三次作业的历练之后终于来到了写博客这一周.回顾开学来的这一个月,令我印象最深刻也是最累的一门课就是OO了.虽然上学期学过一部分Java,但这学期开学就来的OO作业还是让我在第二周就开始熬夜了.不过 ...

  9. JAVA_SE基础——65.StringBuffer类 ②

    字符串特点:字符串是常量:它们的值在创建之后不能更改.    字符串的内容一旦发生了变化,那么马上会创建一个新 的对象.    注意: 字符串的内容不适宜频繁修改,因为一旦修改马上就会创建一个新的对象 ...

  10. JAVA_SE基础——16.方法

    接触过C语言的同学,这小章节很容易接受.Java中的方法是类似与C语言中的函数  功能和调用方法都类似  只不过叫法不一样  因为java是面向对象  c是面向过程    仅仅是叫法不同.. . 看到 ...