zoukankan      html  css  js  c++  java
  • 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个参数:

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

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

    关于分段锁

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

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

    jdk1.8的map实现

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

    什么时候扩容?

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

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

    当数组大小已经超过64并且链表中的元素个数超过默认设定(8个)时,将链表转化为红黑树

    ConcurrentHashMap的put操作代码如下:

    把数组中的每个元素看成一个桶。可以看到大部分都是CAS操作,加锁的部分是对桶的头节点进行加锁,锁粒度很小。

    为什么不用ReentrantLock而用synchronized ?

    • 减少内存开销:如果使用ReentrantLock则需要节点继承AQS来获得同步支持,增加内存开销,而1.8中只有头节点需要进行同步。
    • 内部优化:synchronized则是JVM直接支持的,JVM能够在运行时作出相应的优化措施:锁粗化、锁消除、锁自旋等等。

    总结:

    通过源码可以看出 使用 CAS + synchronized 方式时 加锁的对象是每个链条的头结点,也就是 锁定 的是冲突的链表,所以再次提高了并发度,并发度等于链表的条数或者说 桶的数量。那为什么sement 不把段的大小设置为一个桶呢,因为在粒度比较小的情况下,如果使用ReentrantLock则需要节点继承AQS来获得同步支持,增加内存开销,而1.8中只有头节点需要进行同步,粒度表较小,相对来说内存开销就比较大。所以不把segment的大小设置为一个桶。

    参考

    原文地址:https://cloud.tencent.com/developer/article/1509556

    如有侵权,留言删除

     
     
  • 相关阅读:
    转:testlink 环境搭建(傻瓜版)
    转最简便安装python+selenium-webdriver环境方法
    转发 python中file和open有什么区别
    一面cvte
    org.apache.hadoop.security.AccessControlException: Permission denied:
    让hadoop-0.20.2自带的eclipse插件支持eclipse-3.5以上
    在VMWare中建立Hadoop虚拟集群的详细步骤(使用CentOS)
    第一天
    执行insmod提示invalidmodule format
    Linux Kernel中函数命名
  • 原文地址:https://www.cnblogs.com/hi3254014978/p/12335100.html
Copyright © 2011-2022 走看看