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: 读书笔记 --- ...
随机推荐
- 1.在html中引入js文件和Jquery框架
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- MySQL(动态执行SQL)
day61 防sql注入 delimiter \\ CREATE PROCEDURE p4 ( ), in arg int ) BEGIN set @xo = arg; PREPARE xxx FRO ...
- zoj4016 Mergeable Stack
题意:对n个栈,有q次操作.每个操作可能为三种情况中的一种:1.将v插入到s栈的顶端:2.输出s栈的栈顶(若栈为空则输出empty):3.将栈t插入到栈s的栈顶. 开始考虑到指针可能会mle,用数组模 ...
- 微信小程序redirect 到tab不刷新
// 更新2018/11/20:现在小程序的页面栈长度为10 更正 2018/11/20: 经过一段时间的实践,我发现以前方法存在很多问题,比如 getCurrentPages 方法并不在官方的 AP ...
- ASP.NET MVC Forms验证机制
ASP.NET MVC 3 使用Forms身份验证 身份验证流程 一.用户登录 1.验证表单:ModelState.IsValid 2.验证用户名和密码:通过查询数据库验证 3.如果用户名和密码正确, ...
- D07——C语言基础学PYTHON
C语言基础学习PYTHON——基础学习D07 20180826内容纲要: 面向对象进阶学习 1 静态方法 2 类方法 3 属性方法 4 类的特殊成员方法(本节重点) 5 反射(本节重点) 6 异常(本 ...
- 解决ASP.NET MVC 下使用SQLite 报no such table的问题
观察后发现项目中数据库的存放位置不正确. Web项目添加到App_Data文件夹下, 文件始终不复制 Web.Config文件下的连接字符串 <add name="SQLiteconn ...
- 拦截并记录数据库操作-Logging and Intercepting Database Operations
原文:http://msdn.microsoft.com/zh-cn/data/dn469464 Logging and Intercepting Database Operations Starti ...
- Java_try,catch,finally return之间的执行顺序
以往认为函数只要执行到return语句便会返回结果并终止,然而这时错误的,因为这存在特例. 掌握下面几条原则就可以完全解决“当try.catch.finally遭遇return”的问题. 原则:1.f ...
- Java跨语言调用,使用JNA访问Java外部接口
1. JNA简单介绍 先说JNI(Java Native Interface)吧,有过不同语言间通信经历的一般都知道,它允许Java代码和其他语言(尤其C/C++)写的代码进行交互,只要遵守调用约定即 ...