java8的ConcurrentHashMap为何放弃分段锁,为什么要使用CAS+Synchronized取代Segment+ReentrantLock
原文地址:https://cloud.tencent.com/developer/article/1509556
推荐一篇 ConcurrentHashMap 和 HashMap 写的比较的的文章
jdk1.7分段锁的实现
和hashmap一样,在jdk1.7中ConcurrentHashMap的底层数据结构是数组加链表。和hashmap不同的是ConcurrentHashMap中存放的数据是一段段的,即由多个Segment(段)组成的。每个Segment中都有着类似于数组加链表的结构。
关于Segment
ConcurrentHashMap有3个参数:
- initialCapacity:初始总容量,默认16
- loadFactor:加载因子,默认0.75
- concurrencyLevel:并发级别,默认16
其中并发级别控制了Segment的个数,在一个ConcurrentHashMap创建后Segment的个数是不能变的,扩容过程过改变的是每个Segment的大小。
关于分段锁
段Segment继承了重入锁ReentrantLock,有了锁的功能,每个锁控制的是一段,当每个Segment越来越大时,锁的粒度就变得有些大了。
- 分段锁的优势在于保证在操作不同段 map 的时候可以并发执行,操作同段 map 的时候,进行锁的竞争和等待。这相对于直接对整个map同步synchronized是有优势的。
- 缺点在于分成很多段时会比较浪费内存空间(不连续,碎片化); 操作map时竞争同一个分段锁的概率非常小时,分段锁反而会造成更新等操作的长时间等待; 当某个段很大时,分段锁的性能会下降。
jdk1.8的map实现
和hashmap一样,jdk 1.8中ConcurrentHashmap采用的底层数据结构为数组+链表+红黑树的形式。数组可以扩容,链表可以转化为红黑树。
什么时候扩容?
- 当前容量超过阈值
- 当链表中元素个数超过默认设定(8个),当数组的大小还未超过64的时候,此时进行数组的扩容,如果超过则将链表转化成红黑树
什么时候链表转化为红黑树?
当数组大小已经超过64并且链表中的元素个数超过默认设定(8个)时,将链表转化为红黑树
ConcurrentHashMap的put操作代码如下:

把数组中的每个元素看成一个桶。可以看到大部分都是CAS操作,加锁的部分是对桶的头节点进行加锁,锁粒度很小。
为什么不用ReentrantLock而用synchronized ?
- 减少内存开销:如果使用ReentrantLock则需要节点继承AQS来获得同步支持,增加内存开销,而1.8中只有头节点需要进行同步。
- 内部优化:synchronized则是JVM直接支持的,JVM能够在运行时作出相应的优化措施:锁粗化、锁消除、锁自旋等等。
总结:
参考
- https://my.oschina.net/pingpangkuangmo/blog/817973
- https://www.wanaright.com/2018/09/30/java10-concurrenthashmap-no-segment-lock/
- https://blog.csdn.net/mian_csdn/article/details/70185104
- https://cloud.tencent.com/developer/article/1509556
原文地址:https://cloud.tencent.com/developer/article/1509556
如有侵权,留言删除
java8的ConcurrentHashMap为何放弃分段锁,为什么要使用CAS+Synchronized取代Segment+ReentrantLock的更多相关文章
- ConcurrentHashMap 1.8为什么要使用CAS+Synchronized取代Segment+ReentrantLock
大家应该都知道ConcurrentHashMap在1.8的时候有了很大的改动,当然,我这里要说的改动不是指链表长度大于8就转为红黑树这种常识,我要说的是ConcurrentHashMap在1.8为什么 ...
- JDK8的 CHM 为何放弃分段锁
概述 我们知道, 在 Java 5 之后,JDK 引入了 java.util.concurrent 并发包 ,其中最常用的就是 ConcurrentHashMap 了, 它的原理是引用了内部的 Seg ...
- 分段锁——ConcurrentHashMap
1.线程不安全的HashMap因为多线程环境下,使用Hashmap进行put操作会引起死循环,导致CPU利用率接近100%,所以在并发情况下不能使用HashMap. 2.效率低下的HashTable容 ...
- java8中ConcurrentHashMap
HashMap的线程不安全主要体现在resize时的死循环及使用迭代器时的fast-fail上. Fast-fail: fail-fast 机制是java集合(Collection)中的一种错误机制. ...
- Java8 中 ConcurrentHashMap工作原理的要点分析
简介: 本文主要介绍Java8中的并发容器ConcurrentHashMap的工作原理,和其它文章不同的是,本文重点分析了不同线程的各类并发操作如get,put,remove之间是如何同步的,以及这些 ...
- Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等
Java 中15种锁的介绍 Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等,在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类 ...
- 学习ConcurrentHashMap1.7分段锁原理
1. 概述 接上一篇 学习 ConcurrentHashMap1.8 并发写机制, 本文主要学习 Segment分段锁 的实现原理. 虽然 JDK1.7 在生产环境已逐渐被 JDK1.8 替代,然而一 ...
- redis分布式锁扣减库存弊端: 吞吐量低, 解决方法:使用 分段锁 分布式分段锁并发扣减库存--代码实现
package tech.codestory.zookeeper.aalvcai.ConcurrentHashMapLock; import lombok.AllArgsConstructor; im ...
- 锁开销优化以及 CAS 简单说明
锁开销优化以及 CAS 简单说明 锁 互斥锁是用来保护一个临界区,即保护一个访问共用资源的程序片段,而这些共用资源又无法同时被多个线程访问的特性.当有线程进入临界区段时,其他线程或是进程必须等待. 在 ...
随机推荐
- R语言入门:向量的运算
向量之间的加减乘除运算: > x <- 1 > x [1] 1 2 3 4 5 6 7 8 9 10 > x=x+1 > x [1] 2 3 4 5 6 7 8 9 10 ...
- SpringBoot安全管理--(三)整合shiro
简介: Apache Shiro 是一一个开源的轻量级的Java安全框架,它提供身份验证.授权.密码管理以及会话管理等功能. 相对于Spring Security, Shiro框架更加直观.易用,同时 ...
- 大白话工厂方法模式(Factory Method)
目录 简单工厂模式缺陷 简单工厂模式改造 工厂方法模式定义 工厂方法模式结构 工厂方法模式分析 参考文献 简单工厂模式缺陷 大白话简单工厂模式(Simple Factory Pattern)中通过买车 ...
- openlayers6实现webgl点图层渲染效果(附源码下载)
前言:openlayers6推出来的有一段时间,推出来的新特性见:https://github.com/openlayers/openlayers/releases/该版本的主要功能是能够组合具有不同 ...
- O2O外卖玩众包 开放平台难解标准之痛
开放平台难解标准之痛" title="O2O外卖玩众包 开放平台难解标准之痛"> 有一种怪现象一直是国内互联网企业摆脱不了的附骨之疽--不管规模大小,总是削尖了脑 ...
- MySql概述及入门(五)
MySql概述及入门(五) MySQL集群搭建之读写分离 读写分离的理解 为解决单数据库节点在高并发.高压力情况下出现的性能瓶颈问题,读写分离的特性包括会话不开启事务,读语句直接发送到 salve 执 ...
- python中class的定义及使用
#类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法. #对象:它是类的实例化. #方法:类中定义的函数. #类(Class) 由3个部分构成: ...
- .NET知识梳理——6.lambda
1. lambda 1.1 匿名方法lambda表达式 Lambda表达式 Lambda是一个匿名方法,实例化委托的一个参数,编译的时候会产生一个密封类,同时增加一个方法. Lambda ...
- Selenium实战(四)——unittest单元测试2(断言方法+discover()多测试用例的执行)
一.断言方法 方法 检查 版本 assertEqual(a,b) a==b assertNotEqual(a,b) a!=b assertTrue(x) bool(x) is True a ...
- java课后作业10.14
一.简单总结一下java中类的初始化的规律: 1.类的构造函数优先 2.初始化块儿和定义时候的赋值,这俩个初始化方法优先级是一样的,在程序中谁最后执行,那么程序就采用谁的初始化值. 二.在java中想 ...