HashMap线程不安全 | 线程安全的 ConcurrentHashMap

Posted 做猪呢,最重要的是开森啦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HashMap线程不安全 | 线程安全的 ConcurrentHashMap相关的知识,希望对你有一定的参考价值。

0. HashMap是线程不安全的:

   JDK1.8之前多线程同时进行put操作,并且同时进行扩容的时候可能会出现环形链表,导致死循环的发生
·
 【原因】:扩容采用的是“头插法”,会导致同一索引位置的节点在扩容后顺序反掉。

   JDK1.8后采用的是“尾插法”,所以扩容时不存在死循环问题,但在链表转换树或者对树进行操作的时候会出现线程安全的问题。
·
 【参考】:HashMap在jdk1.8也会出现死循环的问题

   当然,HashMap在迭代遍历循环中修改集合结构,都会报并发修改异常ConcurrentModificationException
·
 【参考】:集合遍历修改ConcurrentModificationException异常

1. HashTable的线程安全:

 HashTable是线程安全的,因为它的方法都是同步方法,即synchronize修饰的

在这里插入图片描述

2. Collections.synchronizedMap(hashMap)的线程安全:

   利用工具类Collections将线程不安全的map转换为线程安全的map。
·
 【原理】:Collections的内部类SynchronizedMap引入mutex对象,所有map操作都通过同步代码块进行,锁住的是mutex对象。

在这里插入图片描述

3. ConcurrentHashMap的线程安全:

 3.1. ConcurrentHashMap 1.7:
  • 底层:数组(Segment)+ 数组(HashEntry)+ 链表(HashEntry节点)
  • put操作:头插链表
  • 原理:通过ReentrantLock锁住Segments数组对象,只要在不同Segments的节点数据,就能并发安全操作
  • Segment的个数一旦初始化就不能改变,默认Segment的个数是16,所以JDK1.7 默认支持最多16个线程并发
 3.2. ConcurrentHashMap 1.8:
  • 底层:Node数组 + 链表 + 红黑树
  • put操作:尾插链表
  • 原理:锁住的是链表头节点对象,通过CAS和synchronize来保证线程安全。JDK1.8引入synchronize锁升级策略,性能和Lock差不多了
  • 和HashMap一样,链表大于8且Node数组大于64就会转红黑树。

 相对于JDK1.7 之恶杰锁住的是链表头节点,而不是分段数组Segments,锁粒度变小,并发能力变高

以上是关于HashMap线程不安全 | 线程安全的 ConcurrentHashMap的主要内容,如果未能解决你的问题,请参考以下文章

hashmap多线程不安全的原因

HashMap线程不安全 | 线程安全的 ConcurrentHashMap

HashMap线程不安全 | 线程安全的 ConcurrentHashMap

hashMap线程不安全的原因及表现

Java并发多线程编程——集合类线程不安全之HashMap的示例及解决方案

ConcurrentHashMap-----不安全线程hashmap-安全线程-hashtable