ConcurrentHashMap的源码分析-JDK1.7和Jdk1.8版本的变化
ConcurrentHashMap和HashMap的实现原理是差不多的,但是因为ConcurrentHashMap需要支持并发操作,所以在实现上要比hashmap稍微复杂一些。
在JDK1.7的实现上,ConrruentHashMap由一个个Segment组成,简单来说,ConcurrentHashMap是一个Segment数组,它通过继承ReentrantLock来进行加锁,通过每次锁住一个segment来保证每个segment内的操作的线程安全性从而实现全局线程安全。整个结构图如下
当每个操作分布在不同的segment上的时候,默认情况下,理论上可以同时支持16个线程的并发写入
相比于1.7版本,它做了两个改进
1. 取消了segment分段设计,直接使用Node数组来保存数据,并且采用Node数组元素作为锁来实现每一行数据进行加锁来进一步减少并发冲突的概率
2. 将原本数组+单向链表的数据结构变更为了数组+单向链表+红黑树的结构。为什么要引入红黑树呢?在正常情况下,key hash之后如果能够很均匀的分散在数组中,那么table数组中的每个队列的长度主要为0或者1.但是实际情况下,还是会存在一些队列长度过长的
情况。如果还采用单向列表方式,那么查询某个节点的时间复杂度就变为O(n); 因此对于队列长度超过8的列表,JDK1.8采用了红黑树的结构,那么查询的时间复杂度就会降低到O(logN),可以提升查找的性能;
这个结构和JDK1.8版本中的Hashmap的实现结构基本一致,但是为了保证线程安全性,ConcurrentHashMap的实现会稍微复杂一下。接下来我们从源码层面来了解一下它的原理.
我们基于put和get方法来分析它的实现即可
put方法第一阶段
public V put(K key, V value) { return putVal(key, value, false);
}
假如在上面这段代码中存在两个线程,在不加锁的情况下:线程A成功执行casTabAt操作后,随后的线程B可以通过tabAt方法立刻看到table[i]的改变。原因如下:线程A的casTabAt操作,具有volatile读写相同的内存语义,根据volatile的happens-before规则:线程A的casTabAt操作,一定对线程B的tabAt操作可见
ConcurrentHashMap的源码分析-JDK1.7和Jdk1.8版本的变化相关推荐
- HashMap与ConcurrentHashMap万字源码分析
HashMap与ConcurrentHashMap`源码解析 JDK版本:1.7 & 1.8 开发中常见的数据结构有三种: 1.数组结构:存储区间连续.内存占用严重.空间复杂度大 优点:因 ...
- TreeMap源码分析——深入分析(基于JDK1.6)
TreeMap有Values.EntrySet.KeySet.PrivateEntryIterator.EntryIterator.ValueIterator.KeyIterator.Descendi ...
- ConcurrentHashMap的源码分析-transfer
扩容是ConcurrentHashMap的精华之一,扩容操作的核心在于数据的转移,在单线程环境下数据的转移很简单,无非就是把旧数组中的数据迁移到新的数组.但是这在多线程环境下,在扩容的时候其他线程也可 ...
- [集合]ConcurrentHashMap的源码分析
前言: 强推:一文读懂HashMap 这感觉讲的HashMap很明白. 1. 多线程环境下面,HashMap和Hashtable会怎么样? 1.1 HashMap 因为put会调用: // 新增Ent ...
- ConcurrentHashMap的源码分析-高低位原理分析
ConcurrentHashMap在做链表迁移时,会用高低位来实现,这里有两个问题要分析一下 1. 如何实现高低位链表的区分 假如我们有这样一个队列 第14个槽位插入新节点之后,链表元素个数已经达到了 ...
- ConcurrentHashMap的源码分析-CounterCells解释
ConcurrentHashMap是采用CounterCell数组来记录元素个数的,像一般的集合记录集合大小,直接定义一个size的成员变量即可,当出现改变的时候只要更新这个变量就行.为什么Concu ...
- ConcurrentHashMap的源码分析-为什么要做高低位的划分
要想了解这么设计的目的,我们需要从ConcurrentHashMap的根据下标获取对象的算法来看,在putVal方法中1018行 (f = tabAt(tab, i = (n - 1) & h ...
- ConcurrentHashMap的源码分析-扩容过程图解
ConcurrentHashMap支持并发扩容,实现方式是,把Node数组进行拆分,让每个线程处理自己的区域,假设table数组总长度是64,默认情况下,那么每个线程可以分到16个bucket. 然后 ...
- ConcurrentHashMap的源码分析-resizeStamp
这块逻辑要理解起来,也有一点复杂. resizeStamp用来生成一个和扩容有关的扩容戳,具体有什么作用呢?我们基于它的实现来做一个分析 static final int resizeStamp(in ...
最新文章
- redis删除过期key的算法_面试官别再问我Redis内存满了该怎么办了
- 那些你所不知道的arXiv使用技巧
- PyCharm编写shell脚本无法运行
- 技术分享 | 混合云模式下SaaS端前端最佳实践
- [ubuntu]deb软件源
- Java通过FFMPEG获取视频时长
- 329.矩阵中的最长递增路径
- Windows XP终极优化设置(精心整理)
- 2021上半年软考数据库系统工程师真题完整版
- Linux平台升级chrome浏览器后,再打开会提示:“您的个人资料来自新版 Google Chrome 浏览器,因此无法使用。某些功能可能无法使用。请指定其他个人资料目录,或使用新版本”
- 算法导论适合c语言吗,看《算法导论》需要多好的数学基础?
- ERP基础数据 华夏
- 微信公众号自定义服务器,微信公众号自定义服务器的第一次验证
- java excel 数据有效性_Excel设置数据有效性实现单元格下拉菜单的3种方法
- 把字符串转换大写php,php把字符串转换为大写的函数strtoupper()
- Brain:一种用于阿尔兹海默症(AD)分类的可解释的深度学习框架
- android圆角设置
- 程序员业务,微信全文搜索技术优化
- photoshop时钟制作过程
- 在北京工作了两年,现在跳槽到了广州,社保公积金该如何办理?
热门文章
- 随时间的反向传播算法 BPTT
- 一队老耗子,每个月都生一对小耗子,小耗子长3个月,第四个月开始变成老耗子开始生, 		// 假设所有耗子都不死,请问20个月之后共有多少只耗子?...
- [Windows]查看运行进程的参数【wmic】
- iOS原生WebView中JavaScript和OC交互
- 再回首Java第十一天
- UVa 11027 - Palindromic Permutation 回文串,组合加搜索
- 多给明年留些钱 明年必将要火的好手机
- 收集下关系数据库处理亿万级别的数据
- 前瞻:Java能否畅行未来?
- Java解析Excel工具类(兼容xls和xlsx)