本文来源于翁舒航的博客,点击即可跳转原文观看!!!(被转载或者拷贝走的内容可能缺失图片、视频等原文的内容)

若网站将链接屏蔽,可直接拷贝原文链接到地址栏跳转观看,原文链接: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原理

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原理解析的更多相关文章

  1. 【Java并发编程】1、ConcurrentHashMap原理分析

    集合是编程中最常用的数据结构.而谈到并发,几乎总是离不开集合这类高级数据结构的支持.比如两个线程需要同时访问一个中间临界区(Queue),比如常会用缓存作为外部文件的副本(HashMap).这篇文章主 ...

  2. 【Java并发编程】23、ConcurrentHashMap原理分析(1.7和1.8版本对比)

    jdk 1.8版本 ConcurrentHashMap在1.8中的实现,相比于1.7的版本基本上全部都变掉了.首先,取消了Segment分段锁的数据结构,取而代之的是数组+链表(红黑树)的结构.而对于 ...

  3. Java并发编程的艺术(四)——线程的状态

    线程的状态 初始态:NEW 创建一个Thread对象,但还未调用start()启动线程时,线程处于初始态. 运行态:RUNNABLE 在Java中,运行态包括就绪态 和 运行态. 就绪态 该状态下的线 ...

  4. 《Java并发编程的艺术》读书笔记:二、Java并发机制的底层实现原理

    二.Java并发机制底层实现原理 这里是我的<Java并发编程的艺术>读书笔记的第二篇,对前文有兴趣的朋友可以去这里看第一篇:一.并发编程的目的与挑战 有兴趣讨论的朋友可以给我留言! 1. ...

  5. Java并发编程的艺术,解读并发编程的优缺点

    并发编程的优缺点 使用并发的原因 多核的CPU的背景下,催生了并发编程的趋势,通过并发编程的形式可以将多核CPU的计算能力发挥到极致,性能得到提升. 在特殊的业务场景下先天的就适合于并发编程. 比如在 ...

  6. 读书笔记之《Java 并发编程的艺术》

    一.多线程语义 即使是单核处理器也支持多线程执行代码,CPU 通过给每个线程分配 CPU 时间片来执行任务,当前任务执行一个时间片后会切换到下一个任务,所以 CPU 通过不停的切换线程执行. 并发执行 ...

  7. Java并发编程:Synchronized及其实现原理

    Java并发编程系列: Java 并发编程:核心理论 Java并发编程:Synchronized及其实现原理 Java并发编程:Synchronized底层优化(轻量级锁.偏向锁) Java 并发编程 ...

  8. 读《Java并发编程的艺术》(一)

    离开博客园很久了,自从找到工作,到现在基本没有再写过博客了.在大学培养起来的写博客的习惯在慢慢的消失殆尽,感觉汗颜.所以现在要开始重新培养起这个习惯,定期写博客不仅是对自己学习知识的一种沉淀,更是在督 ...

  9. Java并发编程的艺术读书笔记(2)-并发编程模型

    title: Java并发编程的艺术读书笔记(2)-并发编程模型 date: 2017-05-05 23:37:20 tags: ['多线程','并发'] categories: 读书笔记 --- 1 ...

  10. Java并发编程的艺术读书笔记(1)-并发编程的挑战

    title: Java并发编程的艺术读书笔记(1)-并发编程的挑战 date: 2017-05-03 23:28:45 tags: ['多线程','并发'] categories: 读书笔记 --- ...

随机推荐

  1. day 57 Bootstrap 第一天

    一 .bootstrap是什么  http://v3.bootcss.com/css/#grid-options(参考博客) 是一个前端开发的框架. HTML CSS JS 下载地址:https:// ...

  2. “全栈2019”Java多线程第十九章:死锁详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java多 ...

  3. storm配置详解

    storm的配置文件在${STORM_HOME}/conf/storm.yaml.下面详细说明storm的配置信息. java.libary.path:storm本身依赖包的路径,有多个路径的时候使用 ...

  4. sublime text3---Emmet:HTML/CSS代码快速编写神器

    Emmet的前身是大名鼎鼎的Zen coding,如果你从事Web前端开发的话,对该插件一定不会陌生.它使用仿CSS选择器的语法来生成代码,大大提高了HTML/CSS代码编写的速度,比如下面的演示: ...

  5. 七:MyBatis学习总结(七)——Mybatis缓存

    ---恢复内容开始--- 一.MyBatis缓存介绍 正如大多数持久层框架一样,MyBatis 同样提供了一级缓存和二级缓存的支持 一级缓存: 基于PerpetualCache 的 HashMap本地 ...

  6. 多线程学习:Volatile与Synchronized的区别、什么是重排序

    java线程的内存模型 java的线程内存模型中定义了每个线程都有一份自己的共享变量副本(本地内存),里面存放自己私有的数据,其他线程不能直接访问,而一些共享变量则存在主内存中,供所有线程访问. 上图 ...

  7. Nginx基本入门

    转自:http://blog.csdn.net/u012486840/article/details/53098890 1.静态HTTP服务器 首先,Nginx是一个HTTP服务器,可以将服务器上的静 ...

  8. 使用ggbio在R中制作弦图

    分享一个制作弦图的R包:ggbio. 以下是一个简单的使用实例,效果图和代码如下. library(GenomicRanges) set.seed(1) N <- 100 gr <- GR ...

  9. litespeed 下配置 伪静态,反向代理

    <IfModule mod_rewrite.c>RewriteEngine onRewriteBase / RewriteRule ^(.*).html$ index.php?static ...

  10. Ubuntu11.10 带图形安装步骤详解

    不多说,直接上干货! 成功!  关于Ubuntu的网络设置.静态IP设置,见 Ubuntukylin-14.04-desktop( 不带分区)安装步骤详解 Ubuntukylin-14.04-desk ...