美文网首页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