java并发编程的艺术(四)---ConcurrentHashMap原理解析
本文来源于翁舒航的博客,点击即可跳转原文观看!!!(被转载或者拷贝走的内容可能缺失图片、视频等原文的内容)
若网站将链接屏蔽,可直接拷贝原文链接到地址栏跳转观看,原文链接:https://www.cnblogs.com/wengshuhang/p/10240309.html
由来:
我们都知道,hashmap是线程不安全的,所以在多线程情况下无法使用这个数据结构,hashTable是线程安全的,但是它的底层实现只是在hashmap基础上进行了
synchronized的加锁,这种加锁方式效率低下,所以就有了ConcurrentHashMap的出现。
数据结构:
ConcurrentHashMap是由Segment数组(继承了锁ReentrantLock)跟HashEntry数组结构构成的,默认情况下拥有16个Segment数组(可以看成hashmap),每个segment数组里都有一个hashEntry数组,也就是数据+链表/红黑树结构,这点跟hashmap就是一样的了。当要修改hashEntry数组中的元素时候,就需要获取这个segment的锁,从而实现分段锁机制,利用分段锁来提高锁的效率。
笔者阅读到这里时候,发现 JDK1.8源码跟书上所介绍的内容有些不一样了,查阅资料才发现,1.8已经做了一些比较大的改动。
jdk1.8: JDK1.8的实现已经摒弃了Segment的概念,而是直接用Node数组+链表+红黑树的数据结构来实现,并发控制使用Synchronized和CAS来操作,整个看起来就像是优化过且线程安全的HashMap,虽然在JDK1.8中还能看到Segment的数据结构,但是已经简化了属性,只是为了兼容旧版本。
写到这里,我发现有篇博客写的很好,直接转载了
ConcurrentHashmap原理链接:https://www.cnblogs.com/wengshuhang/articles/10243204.html
虽然人家写的好,但是重点的地方我还是自己亲手再写一遍吧,加深印象:
常量设计:
node数组的最高容量2^30,
存放node数组的对象。
其他常量跟hashmap倒是差不多, 初始默认容量都为16,加载因子是0.75, 链表转红黑树的阈值是8 , 树转链表的阈值是 6
控制标识符,用来控制table的初始化和扩容的操作,不同的值有不同的含义。
源码:
node数组,点进去看node就是个简单的链表,但是只能读取,不允许修改


TreeNode:TreeNode继承与Node,但是数据结构换成了二叉树结构,它是红黑树的数据的存储结构,用于红黑树中存储数据,当链表的节点数大于8时会转换成红黑树的结构,他就是通过TreeNode作为存储结构代替Node来转换成黑红树源代码如下

TreeBin从字面含义中可以理解为存储树形结构的容器,而树形结构就是指TreeNode,所以TreeBin就是封装TreeNode的容器,它提供转换黑红树的一些条件和锁的控制,部分源码结构如下

我们接下来看看concurrentHashmap的最常用的put,get操作。首先,concurrentHashmap的初始化操作并不会实例 map中的各个对象,它属于懒加载的类型,就像单例模式,当真正要用到的时候才会去初始化类中的各个对象。


我们能看到 第一个判断,倘若没有 实例tab ,便去初始化table initTable(),,若i位置没有数据则直接无锁插入。initTable中的代码主要就是初始化map类中的table参数跟sizeCtl参数(这两个参数上文有介绍)

其次验证node的hash值(f.hash == noved),若需要扩容则扩容。
若不满足上诉条件则最后进行synchronized加锁操作,对链表或红黑树的头个节点进行加锁,这样就达到了分段式加锁的最初目的,从而抛弃了segment的锁。然后再验证数据结构是链表还是红黑树分开处理。
借原文归纳总结一番

看完感觉最厉害的核心就是当出现同步状态时候,可以调用多个线程一起去并发扩容,通过标志位advance跟CAS插入来保证多个工作线程来一起进行数组的复制扩容,从而节约了计算机的线程资源,不得不佩服jdk的大牛们的思想,在底层就做了这么好的优化。
接下来我们看看链表是怎么转化为红黑树的,当链表长度大于8时,就会转化为红黑树。


而当数组长度不大于64时候,不进行数据的转换,而是进行了数组的扩容操作,因为当容量变大之后,hash冲突也就自然少了,这个阈值扩容可以减少hash冲突,不必要去转红黑树。
而get的操作比较简单


最后不得不说一句,原文作者写的真是太好了,推荐大家看一遍原文,我这边记录的比较不完整。
总结:

java并发编程的艺术(四)---ConcurrentHashMap原理解析的更多相关文章
- 【Java并发编程】1、ConcurrentHashMap原理分析
集合是编程中最常用的数据结构.而谈到并发,几乎总是离不开集合这类高级数据结构的支持.比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap).这篇文章主 ...
- 【Java并发编程】23、ConcurrentHashMap原理分析(1.7和1.8版本对比)
jdk 1.8版本 ConcurrentHashMap在1.8中的实现,相比于1.7的版本基本上全部都变掉了.首先,取消了Segment分段锁的数据结构,取而代之的是数组+链表(红黑树)的结构.而对于 ...
- Java并发编程的艺术(四)——线程的状态
线程的状态 初始态:NEW 创建一个Thread对象,但还未调用start()启动线程时,线程处于初始态. 运行态:RUNNABLE 在Java中,运行态包括就绪态 和 运行态. 就绪态 该状态下的线 ...
- 《Java并发编程的艺术》读书笔记:二、Java并发机制的底层实现原理
二.Java并发机制底层实现原理 这里是我的<Java并发编程的艺术>读书笔记的第二篇,对前文有兴趣的朋友可以去这里看第一篇:一.并发编程的目的与挑战 有兴趣讨论的朋友可以给我留言! 1. ...
- Java并发编程的艺术,解读并发编程的优缺点
并发编程的优缺点 使用并发的原因 多核的CPU的背景下,催生了并发编程的趋势,通过并发编程的形式可以将多核CPU的计算能力发挥到极致,性能得到提升. 在特殊的业务场景下先天的就适合于并发编程. 比如在 ...
- 读书笔记之《Java 并发编程的艺术》
一.多线程语义 即使是单核处理器也支持多线程执行代码,CPU 通过给每个线程分配 CPU 时间片来执行任务,当前任务执行一个时间片后会切换到下一个任务,所以 CPU 通过不停的切换线程执行. 并发执行 ...
- Java并发编程:Synchronized及其实现原理
Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...
- 读《Java并发编程的艺术》(一)
离开博客园很久了,自从找到工作,到现在基本没有再写过博客了.在大学培养起来的写博客的习惯在慢慢的消失殆尽,感觉汗颜.所以现在要开始重新培养起这个习惯,定期写博客不仅是对自己学习知识的一种沉淀,更是在督 ...
- Java并发编程的艺术读书笔记(2)-并发编程模型
title: Java并发编程的艺术读书笔记(2)-并发编程模型 date: 2017-05-05 23:37:20 tags: ['多线程','并发'] categories: 读书笔记 --- 1 ...
- Java并发编程的艺术读书笔记(1)-并发编程的挑战
title: Java并发编程的艺术读书笔记(1)-并发编程的挑战 date: 2017-05-03 23:28:45 tags: ['多线程','并发'] categories: 读书笔记 --- ...
随机推荐
- S11 day 93 RestFramework 之 序列化
1. 表建模 from django.db import models # Create your models here. #文章表 class Article(models.Model): tit ...
- 七,apache配置域名
配置域名服务器流程: (1)在httpd.conf中启用虚拟主机,Include conf/extra/httpd-vhosts.conf前面的#去掉. (2)在httpd.conf中修改项目路径为自 ...
- grub覆盖mbr引导系统
grub覆盖mbr引导系统 0.个人PC,WIN 7 + Kali,easybcd 不起作用,需要制作 kali 安装盘 PS:推荐使用 universal usb installer 制作. 方案一 ...
- 奇怪的Java题:为什么1000 == 1000返回为False,而100 == 100会返回为True?
如果你运行如下代码: 1 2 3 4 Integer a = 1000, b = 1000; System.out.println(a == b);//1 Integer c = 100, d = ...
- 六:MyBatis学习总结(六)——调用存储过程
一.提出需求 查询得到男性或女性的数量, 如果传入的是0就女性否则是男性 二.准备数据库表和存储过程 create table p_user( id int primary key auto_incr ...
- function参数
expr_without_variable { Z_LVAL($$.u.constant) = ; zend_do_pass_param(&$, ZEND_SEND_VAL, Z_LVAL($ ...
- 【bzoj3224】【Tyvj 1728】 普通平衡树 树状数组
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:1. 插入$x$数2. 删除$x$数(若有多个相同的数,因只删除一个)3. 查询$x$数的排名(若有多个相同的数,因输出最小 ...
- 二叉排序树的理解和实现(Java)
二叉排序树的定义和性质 二叉排序树又称二叉排序树.它或者是一个空树,或者是一个具有下列性质的二叉树: 若它的左子树不空,则左子树上所有节点的值均小于它的根结构的值 若它的右子树不空,则右子树上所有结点 ...
- WPF快速实现XML可视化编辑工具
虽然最近业余时间主要都放在研究AngularJS上了,不过由于正好要帮朋友做一个生成XML的小工具,顺便又温顾了一下WPF.虽然这个时代相对于Web应用和移动App,Windows应用程序是越来越少了 ...
- 启动Storm各个后台进程
启动Storm的所有后台进程.和Zookeeper一样,Storm也是快速失败(fail-fast)的系统,这样Storm才能在 任意时刻被停止,并且当进程重启后被正确地恢复执行.这也是为什么Stor ...