concurrentHashMap为什么是线程安全的?

Posted zqlmianshi

tags:

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

ConcurrentHashMap是线程安全的。它可以被多个线程同时使用而不需要额外的同步措施(比如使用synchronized)来保证线程安全。这是因为ConcurrentHashMap内部使用了一些非常高效的机制来保证线程安全,包括:

  1. 分段锁:ConcurrentHashMap将数据分成多个段,每个段都有自己的锁。这样,在多线程环境下,每个线程只需要获得自己段的锁,而不需要获得整个Map的锁,从而大大减少了锁的竞争。

  2. CAS操作:ConcurrentHashMap内部使用了一些原子操作(比如compare-and-swap)来实现对数据的并发访问和修改。这些操作是原子性的,可以保证在多线程环境下数据的一致性。

  3. 高效的迭代器:ConcurrentHashMap提供了一些高效的迭代器来遍历Map中的数据。这些迭代器是弱一致性的,可以在遍历的同时进行数据的修改,但是可以保证每个元素最多被访问一次,且不会出现重复访问的情况。

综上所述,ConcurrentHashMap通过分段锁、CAS操作和高效的迭代器等技术来保证线程安全,并且具有很高的并发性能。

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,锁粒度变小,并发能力变高

以上是关于concurrentHashMap为什么是线程安全的?的主要内容,如果未能解决你的问题,请参考以下文章

concurrenthashmap怎么实现的分段锁

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

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

java并发包研究之-ConcurrentHashMap

Java 集合框架:ConcurrentHashMap

java并发编程之ConcurrentHashMap