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

 我来答
户如乐9318
2022-07-11 · TA获得超过6665个赞
知道小有建树答主
回答量:2559
采纳率:100%
帮助的人:140万
展开全部

1 扩容时可能造成死循环,扩容时会造成死锁,形成环形链表;或者造成扩容大小不一致等问题
2 多个线程put的时,get的值可能不一致,put的操作不是原子性的
3 删除键值对的时候,会删除刚刚修改的位置元素

扩容操作时:
这个操作会新生成一个新的容量的数组,然后对原数组的所有键值对重新进行计算和写入新的数组,之后指向新生成的数组。
当多个线程同时检测到总数量超过门限值的时候就会同时调用resize操作,各自生成新的数组并rehash后赋给该map底层的数组table,结果最终只有最后一个线程生成的新数组被赋给table变量,其他线程的均会丢失。而且当某些线程已经完成赋值而其他线程刚开始的时候,就会用已经被赋值的table作为原始数组,这样也会有问题。

环形链表的原因: 参考
大概看下transfer:

经过这几步,我们会发现转移的时候是逆序的。假如转移前链表顺序是1->2->3,那么转移后就会变成3->2->1。这时候就有点头绪了,死锁问题不就是因为1->2的同时2->1造成的吗?所以,HashMap 的死锁问题就出在这个 transfer() 函数上。

put时:
在hashmap做put操作的时候会调用到以上的方法。现在假如A线程和B线程同时对同一个数组位置调用addEntry,两个线程会同时得到现在的头结点,然后A写入新的头结点之后,B也写入新的头结点,那B的写入操作就会覆盖A的写入操作造成A的写入操作丢失

删除时: 参考
当多个线程同时操作同一个数组位置的时候,也都会先取得现在状态下该位置存储的头结点,然后各自去进行计算操作,之后再把结果写会到该数组位置去,其实写回的时候可能其他的线程已经就把这个位置给修改过了,就会覆盖其他线程的修改。

补充:
内部Entry数组默认大小是16,默认负载因子是0.75

内部Entry数组大小是2的幂

元素个数超过当前大小*默认因子的时候会扩容到当前大小的2倍

扩容是为了减少单个Entry数组链表的平均长度

HashMap线程不安全的主要因素的put过程中会发生扩容,多个线程会同时操作同一块内存导致

JDK7使用数组+链表方式实现;JDK8使用数组+链表/红黑树的方式实现:链表长度为8,链表转化为红黑树;红黑树节点个数为6,红黑树会转化为链表

已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式