美文网首页RxJava编程语言爱好者Java服务器端编程
ConcurrentHashMap在JDK1.8版本比1.7改进

ConcurrentHashMap在JDK1.8版本比1.7改进

作者: 迦叶_金色的人生_荣耀而又辉煌 | 来源:发表于2020-12-31 07:17 被阅读0次

    上一篇 <<<JDK1.8HashMap源码分析
    下一篇 >>>


    ConcurrentHashMap特点:
    a、支持多线程效率高,默认都分成16个Segments
    b、不止key为null

    Jdk1.7版本和1.8版本的ConcurrentHashMap有何区别

    Jdk1.7版本的ConcurrentHashMap采用分段锁;
    1.底层采用分段锁机制,分成16个不同的Segment,每个Segment独立table有独立是锁, Segment其实就是我们的hashTable
    Segment底层继承ReentrantLock上锁,使用CAS做修改,最大支持64次自旋
    2.根据key计算index存放在Segment位置;
    ConcurrentHashMap → Segments(16 个HashTable) → HashEntry
    3.index计算两次
    缺点:
    a、挺占内存的
    b、每个Segment有独立的锁,也会存在等待问题。
    c、需要计算两次index值:第一次计算存放那个Segment对象中 ,第二次计算Segment对象中那个HashEntry<K,V>[] table
    优点:扩容的时候,是每个Segment独立运行,不存在冲突问题,解决了hashmap的死循环问题

     ConcurrentHashMap 1.7 使用Segment+ReentrantLock
    
     ConcurrentHashMap 实际上是HashTable的扩展,调用使用Segment,真正底部是用HashEntry<K,V>单向链表数组
     代码情况:
     class Segment<K,V> extends ReentrantLock,其中Segment中都有HashEntry<K,V>[] table;
    
     HashEntry属性:
      final int hash;
      final K key;
      volatile V val;
      volatile HashEntry<K,V> next;
    
     1、初始化
     默认容量:16
     负载因子:0.75f
    
     2、put方法
     a、如果传入的是空,则抛出异常
     b、计算hash值
       int hash = hash(key);
     c、根据hash判断存放在哪个Segment中
        int j = (hash >>> segmentShift) & segmentMask;
        s = ensureSegment(j);
     c、添加节点 s.put(key, hash, value, false);
      c1、上锁ReentrantLock tryLock()
      c2、加数据
        --如果达到阈值,则扩容:newCapacity = oldCapacity << 1; 2倍方式扩容,扩容后下标重新计算
        --扩容只是针对单个Segment的HashEntry,不影响整体的大小,解决了hashmap的死循环问题
      c3、释放锁ReentrantLock
    

    Jdk1.8版本的ConcurrentHashMap删除了分段锁技术 ,改用CAS无锁机制+synchronized机制。
    1.New Node 采用cas 乐观锁机制保证线程安全性的问题;
    2.如果计算index(只计算一次)产生了冲突 ,使用synchronized上锁;
    --实际上是直接在节点上上锁。

     ConcurrentHashMap 1.8 使用CAS+Synchronized
     CAS是乐观锁,通过自旋,不会造成阻塞。
    
     hashmap在下面语句的时候可能会存在线程安全问题
     tab[i] = newNode(hash, key, value, null);
    
     concurrentmap如何解决线程安全问题:
      1.在创建对象的时候加上了CAS锁
      if (casTabAt(tab, i, null,new Node<K,V>(hash, key, value, null)))
      casTabAt上锁实际方法:U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
      2.如果index产生了冲突,则使用同步锁
      synchronized (f) {}
    
    
     ConcurrentHashMap 实际上是HashTable的扩展,底层使用Node单向链表数组
     属性:
      final int hash;
      final K key;
      volatile V val;
      volatile Node<K,V> next;
    
     默认容量16
    
    比较项目 JDK1.7的ConcurrentHashMap JDK1.8的ConcurrentHashMap
    数据结构 数组+Segments分段锁+HashEntry链表 数组+链表+红黑树(使用Node数组保存数据)
    锁的实现 Lock锁+CAS乐观锁+Unsafe类 取消Segment分段锁设计,使用CAS+Synchronized保证并发风险
    扩容实现 支持多个Segment同时扩容 支持并发扩容

    ConcurrentHashMap 1.8 为什么要使用CAS+Synchronized取代Segment+ReentrantLock

    Segment+ReentrantLock锁住的是单个Segment,也就是单个HashTable,但CAS+Synchronized锁住的是节点,锁的粒度比jdk1.7更加精细;而且JDK1.8的Synchronized性能上也大大的提升了。

    相关文章

      网友评论

        本文标题:ConcurrentHashMap在JDK1.8版本比1.7改进

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