概述

我们知道, 在 Java 5 之后,JDK 引入了 java.util.concurrent 并发包 ,其中最常用的就是 ConcurrentHashMap 了, 它的原理是引用了内部的 Segment ( ReentrantLock )  分段锁,保证在操作不同段 map 的时候, 可以并发执行, 操作同段 map 的时候,进行锁的竞争和等待。从而达到线程安全的目的, 且效率大于 synchronized。

但是在 Java 8 之后, JDK 却弃用了这个分段锁策略,接下来详细学习一下。

一、jdk1.7分段锁的实现

和hashmap一样,在jdk1.7中ConcurrentHashMap的底层数据结构是数组加链表。和hashmap不同的是ConcurrentHashMap中存放的数据是一段段的,即由多个Segment(段)组成的。每个Segment中都有着类似于数组加链表的结构。

1.1 关于Segment

ConcurrentHashMap有3个参数:

  1. initialCapacity:初始总容量,默认16
  2. loadFactor:加载因子,默认0.75
  3. concurrencyLevel:并发级别,默认16

其中并发级别控制了Segment的个数,在一个ConcurrentHashMap创建后Segment的个数是不能变的,扩容过程过改变的是每个Segment的大小。

1.2 关于分段锁

段Segment继承了重入锁ReentrantLock,有了锁的功能,每个锁控制的是一段,当每个Segment越来越大时,锁的粒度就变得有些大了。

  • 分段锁的优势在于保证在操作不同段 map 的时候可以并发执行,操作同段 map 的时候,进行锁的竞争和等待。这相对于直接对整个map同步synchronized是有优势的。
  • 缺点在于分成很多段时会比较浪费内存空间(不连续,碎片化); 操作map时竞争同一个分段锁的概率非常小时,分段锁反而会造成更新等操作的长时间等待; 当某个段很大时,分段锁的性能会下降。

二、jdk1.8的map实现

和hashmap一样,jdk 1.8中ConcurrentHashmap采用的底层数据结构为数组+链表+红黑树的形式。数组可以扩容,链表可以转化为红黑树。

2.1 弃用原因

通过  JDK 的源码和官方文档看来, 他们认为的弃用分段锁的原因由以下几点:

  1. 加入多个分段锁浪费内存空间。
  2. 生产环境中, map 在放入时竞争同一个锁的概率非常小,分段锁反而会造成更新等操作的长时间等待。
  3. 为了提高 GC 的效率.

2.2 什么时候扩容?

  1. 当前容量超过阈值
  2. 当链表中元素个数超过默认设定(8个),当数组的大小还未超过64的时候,此时进行数组的扩容,如果超过则将链表转化成红黑树

2.3 什么时候链表转化为红黑树?

当数组大小已经超过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://cloud.tencent.com/developer/article/1509556

JDK8的 CHM 为何放弃分段锁的更多相关文章

  1. java8的ConcurrentHashMap为何放弃分段锁,为什么要使用CAS+Synchronized取代Segment+ReentrantLock

    原文地址:https://cloud.tencent.com/developer/article/1509556 推荐一篇 ConcurrentHashMap 和 HashMap 写的比较的的文章 j ...

  2. 分段锁——ConcurrentHashMap

    1.线程不安全的HashMap因为多线程环境下,使用Hashmap进行put操作会引起死循环,导致CPU利用率接近100%,所以在并发情况下不能使用HashMap. 2.效率低下的HashTable容 ...

  3. Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等

    Java 中15种锁的介绍 Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等,在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类 ...

  4. 学习ConcurrentHashMap1.7分段锁原理

    1. 概述 接上一篇 学习 ConcurrentHashMap1.8 并发写机制, 本文主要学习 Segment分段锁 的实现原理. 虽然 JDK1.7 在生产环境已逐渐被 JDK1.8 替代,然而一 ...

  5. redis分布式锁扣减库存弊端: 吞吐量低, 解决方法:使用 分段锁 分布式分段锁并发扣减库存--代码实现

    package tech.codestory.zookeeper.aalvcai.ConcurrentHashMapLock; import lombok.AllArgsConstructor; im ...

  6. Java中的各种锁--分类总结

    前言 本文需要具备一定的多线程基础才能更好的理解. 学习java多线程时,最头疼的知识点之一就是java中的锁了,什么互斥锁.排它锁.自旋锁.死锁.活锁等等,细分的话可以罗列出20种左右的锁,光是看着 ...

  7. 50道Java集合经典面试题(收藏版)

    前言 来了来了,50道Java集合面试题也来啦~ 已经上传github: https://github.com/whx123/JavaHome 1. Arraylist与LinkedList区别 可以 ...

  8. Java面试,面试题

    Java面试,面试题 HashMap,HashTable,ConcurrentHash的共同点和区别 HashMap HashTable ConcurrentHashMap ArrayList和Lin ...

  9. Java八股文纯享版——篇②:并发编程

    注: 1.笔记为个人归纳整理,尽力保证准确性,如有错误,恳请指正 2.写文不易,转载请注明出处 3.本文首发地址 https://blog.leapmie.com/archives/c02a6ed1/ ...

随机推荐

  1. nginx反向代理初体验

    需求:部署两台tomcat,默认监听端口分别是8080和8081.访问nginx服务时,自动跳转到相应tomcat服务. 先部署一台机器:就宿主机上tomcat服务: 修改nginx配置:vim ng ...

  2. 一文带你解读Spring5源码解析 IOC之开启Bean的加载,以及FactoryBean和BeanFactory的区别。

    前言 通过往期的文章我们已经了解了Spring对XML配置文件的解析,将分析的信息组装成BeanDefinition,并将其保存到相应的BeanDefinitionRegistry中,至此Spring ...

  3. 『无为则无心』Python面向对象 — 52、私有成员方法(类中行为的封装)

    Python对于类的成员没有严格的访问控制限制,这与其他面向对象的编程语言是有所区别的. 关于私有方法其实和私有属性差不多,有如下要点: 1.通常我们约定,两个下划线开头的方法是私有方法. 2.类内部 ...

  4. 攻防世界Web_shrine

    题目: 给的是源代码,整理一下如下: 看到jinjia flask,render_template_string猜测到这题应该是考查python模板注入. 代码分析可以得到以下信息: 1.路径在 /s ...

  5. 从这3个方面考虑BI工具,选型一选一个准

    BI工具在很多场合都能听到,那么BI工具有什么功能呢?能给企业带来什么?好用的BI工具长什么样?今天跟着小编走近BI工具,一探究竟! 首先要了解BI工具的定义,什么是BI工具.BI工具是指利用现代数据 ...

  6. 三大数据库 sequence 之华山论剑 (中篇)

    sequence 用法四 AUTO INCREMENT 通过 DEFAULT 还是需要手动创建 sequence.有没有更简单的用法呢? 当然,就是通过 AUTO INCREMENT 方式,自动创建 ...

  7. 【C# 表达式树 三】ExpressionType 节点类型种类

    // // 摘要: // 描述表达式目录树的节点的节点类型. public enum ExpressionType { // // 摘要: // 加法运算,如 a + b,针对数值操作数,不进行溢出检 ...

  8. linux 平台实现 web 服务器的自动化发布 (纯shell 版本,存在ssh 不能自动退出问题,待解决)

    转至:https://www.cnblogs.com/vmsky/p/13824172.html 背景说明 1.集团OA系统上线,web App 部署在6台服务器中,因项目初期,每次更新都需要进行大量 ...

  9. Codeforces Round #770 (Div. 2)D

    传送门 题目大意: 交互题, n ( 4 ≤ n ≤ 1000 ) n(4\leq n\leq1000) n(4≤n≤1000)个数字组成的数列 a 1 , a 2 , - , a n ( 0 ≤ a ...

  10. java 读取xlsx文件

    public class ReadExcel { public static void main(String[] args) { Workbook wb = null; Sheet sheet = ...