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线程不安全 | 线程安全的 ConcurrentHashMap
HashMap线程不安全 | 线程安全的 ConcurrentHashMap