HashMap与环的故事

问题:
我们在工作中经常使用HashMap这个数据结构,每一个程序猿都被告诫,这个数据结构不是线程安全的,在单线程操作HashMap的情况下,程序不会问题,但是如果多线程操作同一个HashMap,会出现cpu使用率百分百的情况,这是为什么咧?

1、百度一下的话,网上文章会告诉你答案,cpu使用率达到100%是因为HashMap在多线程并发的情况下entryList出现了环导致的

我们接下来探究,为什么HashMap在多线程并发的情况下entryList会出现了环:其实这一切来源于HashMap的扩容

举个例,这个例子来源一位大佬的分享:
如果两个线程同时对hashMap进行扩容,其中有个线程执行的速度稍微快一点,HashMap扩容代码如下:

 for (int j = 0; j < src.length; j++) {
5:    Entry e = src[j];
6:    if (e != null) {
7:      src[j] = null;
8:      do {
9:      Entry next = e.next;
     // Thread1 STOPS RIGHT HERE
10:     int i = indexFor(e.hash, newCapacity);
11:     e.next = newTable[i];
12:     newTable[i] = e;
13:     e = next;
14:   } while (e != null);
15:   }
16: }

当线程一在第10行(绿色字体)的位置发生了上下文切换, 此时线程一已经设置了节点A(e1)和A的下一个节点是B(next1),如下图所示:
在这里插入图片描述
此时线程一没有移动任何节点,仅仅是分配了一个新的存储桶数组空间(Thread1 buckets)。

此时线程2对HashMap进行了扩容操作,扩容后的entryList,如下图所示 :
在这里插入图片描述
但是此时在线程1中,请注意,e1 和 next1 仍指向相同的节点。但实际上这个节点的指向关系发生了变化。最重要的是,下一个关系被逆转了。也就是说,当 线程1 启动时,它具有节点 A,其下一个节点为节点 B。现在,情况正好相反,节点 B 的下一个节点是节点 A。但是线程1对于线程二的操作并不知情。以下是当线程1获得cpu资源继续往下执行时采取的操作:
在这里插入图片描述


下一次迭代将把 A 放到存储桶 3 列表的前面(毕竟是下一个)。并将它的next节点分配给B,而此时B节点的next节点实际已经分配给了A,产生了环,如下图所示:
在这里插入图片描述
参考资料:
1、http://mailinator.blogspot.com/2009/06/beautiful-race-condition.html
2、https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6423457

引用\[3\]提到,HashMap在1.7版本中没有使用红黑树,而是使用了链表来存储元素。由于使用尾插法,每次都要遍历链表去获取尾节点,这样会耗费性能。而在1.8版本中,HashMap采用了红黑树结构,并且转换条件是链表长度大于8时才会转换成红黑树。这样,遍历链表的次数最大就是8,当超过8时就会转换成红黑树。遍历红黑树的次数取决于树的深度,所以遍历的性能消耗可以忽略不计。这样就解决了头插法循引用的问题。\[3\] 所以,在HashMap 1.7版本中,由于没有使用红黑树,可能会存在的问题。但在1.8版本中,通过使用红黑树结构,并设置了转换阈值为8,可以有效地解决的问题。 #### 引用[.reference_title] - *1* [HashMap1.7 扩容产生形链表](https://blog.csdn.net/weixin_42496727/article/details/124118191)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [HashMap的原理,1.7为什么会形成](https://blog.csdn.net/weixin_41796956/article/details/120562231)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insert_down28v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值