前言
最近在复习hashmap的时候,想到并发下hashmap的非线程安全在所有面试中都有问过,所以特地想写一下文章,尤其针对那些看了好几篇文章看不懂,或者刚入门对这方面云里雾里的朋友,希望我自己提炼的总结和解析能让你茅舍顿开。
什么是hashmap的非线程安全
所谓线程安全,玩过多线程的童鞋,都明白,无非就是在同一时刻,多个操作对同一资源的一系列操作,从而导致最终的结果不一致的情况
- put方面
这块不细说了,就是hash的时候同时塞一个值,数据可能会被覆盖等情况,主要想说说下面这个情况 - rehash方面
我们都知道,hashmap的基本结构就是拉链哈希,但是有一个初始的长度,定的是2的幂次方,同时装载因子,java默认为0.75,一旦超过len*0.75,那么hash开始扩容,并且扩容分为两个步骤:
1. 原始hash桶乘2
2. 将原来hash中所有的数据, 请注意是所有的数据 ,将所有的数据再重新hash到新的扩容好的hash桶当中。
transfer函数
上述图片是rehash中的重要函数,也是出现非线程安全的部分,很简单,只需考虑一种情况:一个线程已经把所有数据rehash了,但是存在某个线程还是持有原来某一个hash数组的头结点引用。
首先把if(hash)这块语句做为分界符:
先来一个B线程,到分界符之前
此时e=Entry2,e.next = Entry3;
分界符之后立马切换到A线程,做完了分界符之后的部分,我们可以看到A线程把原数组的东西重新hash到新的数组中了,发现顺序也是反过来的,在这里假设2,3的重hash在新数组中是同一个位置
此时再切换到B线程,是不是想到,之前的数据还没更新吧,对,就是所谓的还没同步,那么问题就出现了,来分析一下:
e.next = newTable[i]; //此时的newTable[i]是最新的Entry2,而e还是之前没有同步的数据,Entry3,所以这句话导致entry3指向了entry2,形成了死链,最后一张图片就是这句语句的描述。
newTable[i] = e; //e还是Entry3,所以下标3的数组又指回了Entry3,但是死链解不开了。
尽量用了最少语句解释清楚了,希望阅读的朋友多多指教,多多留言,一起进步!
网友评论