HashMap之线程安全问题
我们知道Java8采用的尾插法来代替Java7的头插法,而这种头插法改为尾插法能解决并发状态下,HashMap出现死循环的问题。那么我们现在就来讨论一下为什么HashMap在多线程下是不安全的。
HashMap并发安全问题主要有数据覆盖问题和扩容时死循环
一.数据覆盖问题
JDK7和JDK8都存在这个问题。例如:
- JDK7中A,B线程同时执行put操作时,两个key都指向一个bucket.此时两者都会进行头插法。
- 当A,B都获取到bucket上的头结点时,如果此时A的时间片(时间片轮转法)用完了,线程B便先头插,此时A有时间片了,也准备开始头插
- 但是此时A持有的仍然是老的那个头结点,并没有更新,此时他还以为老的那个头结点仍然存在,于是插入,便覆盖了B的数据
void createEntry(int hash, k key,v value, int bucketIndex){//获取bucket上的头节点Entry<K,v>e= table[bucketIndex];//将新结点作为新的头结点 table[bucketIndexl=new Entry<>(hash, key, value,e);size++;}
Java8的尾插法也涉及到这个问题,所以Java8是为了解决扩容导致死循环的问题
二.扩容导致死循环
有一篇文章写的特别清晰,详情跳转该文章看扩容如何导致死循环:
java关于HashMap多线程扩容导致死循环(JDK1.7)的详细过程
扩容导致死循环的面试简要回答:
一个线程已经完成扩容,此时链表倒置,另一个线程还停留在获取到原头结点及其next语句,而next语义失效,继续执行将导回原头结点,形成死循环