• JDK源码阅读之:JDK8的 CHM 为何放弃分段锁



    概述

    我们知道, 在 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

  • 相关阅读:
    平台调用中的数据封送处理
    JavaScript 中的事件流
    Jquery插件 表格固定表头
    ASP.NET MVC Action Filter与内置的Filter实现
    getCurrentScript的改进
    analyze spring framework source
    Windows Azure: Service Bus Brokered Messaging DeadLetterQueue 使用详解
    C#截图
    权限系统
    音乐播放器
  • 原文地址:https://www.cnblogs.com/xuxh120/p/16044602.html
Copyright © 2020-2023  润新知