美文网首页
1.8 ConcurrentHashMap为何放弃分段代码锁

1.8 ConcurrentHashMap为何放弃分段代码锁

作者: 星空怎样 | 来源:发表于2020-05-29 10:26 被阅读0次

    [toc]

    JDK1.7分段代码锁的实现

    和HashMap一样在1.7中ConcurrentHashMap的底层数据结构是数组加链表,和HashMap不同的是ConcurrentHashMap存放的数据是一段一段的,即由多个Segment组成,每个Segment都有类似的数组加链表的结构。
    关于Segment:

    ConturrentHashMap有三个参数:

    • initialCapacity:容量,初始容量默认16
    • loadFactor:负载因子,默认是0.75
    • concurrentLevel:并发级别默认是16

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

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

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

    JDK1.8的ConcurrentHashMap实现

    和hashMap一样采用了数组链表红黑树的形式数组进行扩容,链表可以转化为红黑树。

    什么时候扩容?

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

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

    当数组大小超过64并且链表中元素个数超过默认8的时候链表转为红黑树,但链表长度小于等于6时候会将红黑树转为链表(红黑树保留链表特性)。

    1.8的线程安全的实现

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

    为什么弃用Segement而用Synchroniized

    • 减少内存开销,如果使用ReentrantLock则需要节点继承AQS来获取同步支持,增加内存开销,而1.8只有头部节点需要进行同步
    • 内部优化:synchronized是jvm直接支持的,jvm能够运行时做出相应的优化措施,锁粗化,锁消除,锁自旋,这使得synchronized能够随着JDK版本升级而不用改动代码前提下获得性能提升。

    相关文章

      网友评论

          本文标题:1.8 ConcurrentHashMap为何放弃分段代码锁

          本文链接:https://www.haomeiwen.com/subject/cxcxzhtx.html