当前位置:首页 > 科技  > 软件

阿里二面:听说过 HashMap 会导致CPU飙升100%吗?

来源: 责编: 时间:2024-05-24 17:24:11 114观看
导读一、问题描述经常有些面试官会问,是否了解过 HashMap 在多线程环境下使用时可能会发生死循环,导致服务器 cpu 100% 的线上故障?关于这个问题,很多年前,在淘宝内网里就有很多的程序员发过这种帖子说一个CPU 被100%了,原因竟

一、问题描述

经常有些面试官会问,是否了解过 HashMap 在多线程环境下使用时可能会发生死循环,导致服务器 cpu 100% 的线上故障?ouM28资讯网——每日最新资讯28at.com

关于这个问题,很多年前,在淘宝内网里就有很多的程序员发过这种帖子说一个CPU 被100%了,原因竟是多线程环境下使用 HashMap 造成的死循环,并且这个事发生了很多次。ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

虽然 Java 官方明确表示,在多线程环境下不推荐使用 HashMap,但是对于这种问题,小编其实也比较意外,如果不是深入的去了解 HashMap,都不知道有这样的问题。ouM28资讯网——每日最新资讯28at.com

为什么会产生死循环呢?下面我们来还原一下问题的经过。ouM28资讯网——每日最新资讯28at.com

二、问题重现

在之前的集合系列文章中,我们了解到 HashMap 是一个哈希数组 + 链表的数据结构,在实际的程序开发中,我们经常会使用到 HashMap,如果对 HashMap 不是很了解,大家可以看小编之前写的《深入浅出分析 HashMap 》一文。ouM28资讯网——每日最新资讯28at.com

HashMap 是一个非线程安全的集合操作类,如果我们的程序操作是单线程的,那么一切都没问题。当我们的程序是多线程操作 HashMap 类时,那么问题就来了,我们一起来复现一下。ouM28资讯网——每日最新资讯28at.com

测试代码,如下:ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

使用了4个线程来向 HashMap 中添加元素,可能一次运行不一定有效果,可以反复运行几次!ouM28资讯网——每日最新资讯28at.com

控制台输出结果:ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

可以清晰的看到,在遍历 map 的内容时,已经死循环了!ouM28资讯网——每日最新资讯28at.com

再来看看,活动监视器,结果如下:ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

cpu 的使用率,直接接近 200%!ouM28资讯网——每日最新资讯28at.com

接下来我们去查看下 java 中刚刚运行的 HashThreadTest 类堆栈情况:ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

可以看到,HashMap 的扩容操作导致了死循环!ouM28资讯网——每日最新资讯28at.com

通过测试,我们发现 HashMap 在多线程环境下进行操作,的确会产生死循环,并且会导致 CPU 100%!ouM28资讯网——每日最新资讯28at.com

这是为什么呢?我们一起来阅读一下源码!ouM28资讯网——每日最新资讯28at.com

三、源码阅读

注意注意,小编在进行测试的时候,使用的是 JDK1.7 的版本!ouM28资讯网——每日最新资讯28at.com

如果你使用 JDK1.8 的版本,不好意思,不一定能复现这个问题!因为 JDK1.8 已经修复了这个问题,但是依然不建议在多线程环境下使用 HashMap!ouM28资讯网——每日最新资讯28at.com

我们继续来看看为什么使用 JDK1.7 会出现这个问题!ouM28资讯网——每日最新资讯28at.com

既然是 put 阶段造成的数据问题,我们不妨一起来看看 HashMap 的 put 过程!ouM28资讯网——每日最新资讯28at.com

1.HashMap 添加过程

HashMap 的 put 源码实现如下:ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

接着我们来看看addEntry()方法,将元素插入到数组中,并且检查容量是否超标,源码实现如下:ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

上面例子中,我们初始化的时候给定的容量是 2,所以在添加元素时必定会扩容!如果超出阀值,就进行扩容处理,创建一个更大容量的 hash 表,然后把从老的 Hash 表中迁移到新的 Hash 表中,源码如下:ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

将旧 hash 表中的元素复制到新的 hash 表中,源码如下:ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

整个 put 过程,大致可以分如下几个步骤:ouM28资讯网——每日最新资讯28at.com

  • 第一步是通过 key 计算出来的 hash 和 equals 来判断元素是否存在,如果存在,直接覆盖;反之,插入;
  • 第二步是将元素插入到 hash 表中,如果不同的元素都在一个 hash 数组下标下,就以链表的形式,采用头插法存储在 hash 节点下;
  • 最后就是判断当前数组容量是否大于扩容阀值,如果大于,就进行扩容处理,然后将旧元素复制到新的数组中;

好了,这个过程基本上没啥问题。ouM28资讯网——每日最新资讯28at.com

我们再来演示一下扩容中重新计算元素 hash 的过程!ouM28资讯网——每日最新资讯28at.com

2.单线程下扩容元素 hash 过程

假设在单线程环境下,我们初始化的时候,给定的数组容量是2,分别添加3个元素,内容如下:ouM28资讯网——每日最新资讯28at.com

  • key=3,value=A;
  • key=4,value=B;
  • key=5,value=C;

源码如下:ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

添加完成之后,数组就会进行扩容处理,扩容后 hash 的容量为原来的2倍,扩容操作流程如下:ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

在单线程环境下,一切看起来都很正常,扩容过程也相当顺利。接下来我们看下并发情况下的扩容。ouM28资讯网——每日最新资讯28at.com

3.多线程扩容元素 hash 过程

假设我们有两个线程,来分别添加3个元素。ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

线程二执行完添加任务之后,在准备将旧元素迁移到新元素的时候,也就是准备 rehash 时,突然被 CPU 挂起,此时阻塞在如下图中的第57行,不再往下执行!而线程一继续执行直到扩容完成。ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

2个线程此时的执行结果,内容如下:ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

接着线程二被唤醒,继续回到第57行执行。ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

此时注意了,我们来详细的分析一下这个过程!ouM28资讯网——每日最新资讯28at.com

第一次循环过程如下:ouM28资讯网——每日最新资讯28at.com

  • 第1步:此时 e 等于{key:3,value:A},next=e.next={key:5,value:C};
  • 第2步:通过 key 重新 hash 计算得到下标 i = 3;
  • 第3步:newTable为局部变量,内容都为null,所以 e.next = newTable[i]=null;
  • 第4步:newTable[i]=e={key:3,value:A};
  • 第5步:e=next={key:5,value:C};

循环结果如下,e={key:5,value:C},满足while()循环条件,接着继续!ouM28资讯网——每日最新资讯28at.com

图片ouM28资讯网——每日最新资讯28at.com

第二次循环过程如下:ouM28资讯网——每日最新资讯28at.com

  • 第1步:此时 e 等于{key:5,value:C},取最新的链表结构,next=e.next={key:3,value:A};
  • 第2步:通过 key 重新 hash 计算得到下标 i = 3;
  • 第3步:在第一次循环中,newTable[i]已经插入值,所以 e.next = newTable[i]={key:3,value:A};
  • 第4步:newTable[i]=e={key:5,value:C};
  • 第5步:e=next={key:3,value:A};

循环结果如下,e={key:3,value:A},满足while()循环条件,接着继续!ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

第三次循环过程如下:ouM28资讯网——每日最新资讯28at.com

  • 第1步:此时 e 等于{key:3,value:A},取最新的链表结构,next=e.next=null;
  • 第2步:通过 key 重新 hash 计算得到下标 i = 3;
  • 第3步:在第二次循环中,newTable[i]已经插入值,所以 e.next = newTable[i]={key:5,value:C};
  • 第4步:newTable[i]=e={key:3,value:A};
  • 第5步:e=next=null;

循环结果如下,e=null,while()程序不在循环!ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

综合线程1、线程2执行结果,最终 hashMap 的存储结果,如下图:ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

可以很清晰的看到,链表发生死循环了!ouM28资讯网——每日最新资讯28at.com

于是,当我们在遍历 hashMap 链表内容的时候,就会出现上文中问题复现的场景,死循环式的输出相同的内容,CPU 直接飙到200%了!ouM28资讯网——每日最新资讯28at.com

对于这种问题,当初有人上报到 SUN 公司,但是 SUN 不认为这是一个问题,因为 HashMap 本来就不支持并发操作!ouM28资讯网——每日最新资讯28at.com

ouM28资讯网——每日最新资讯28at.com

所以,不建议在多线程环境下使用 HashMap,那如果要在多线程环境下使用 map 操作类,该怎么办呢?ouM28资讯网——每日最新资讯28at.com

四、解决办法

办法肯定是有的,如果大家想在多线程场景下使用 HashMap,有两种解决办法:ouM28资讯网——每日最新资讯28at.com

  • 第一种,推荐使用并发包中的 ConcurrentHashMap 类,一种使用分段锁的 hashMap 类,在之后的文章中,咱们也会介绍到它。
  • 另一种,是使用Collections.synchronizedMap(Mao<K,V> map)工具方法,将 HashMap 变成一个线程安全的 map,其实就是对 map 中的方法进行加锁处理,保证多线程下操作安全!

本文链接:http://www.28at.com/showinfo-26-90663-0.html阿里二面:听说过 HashMap 会导致CPU飙升100%吗?

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 敏捷的数据工程实践

下一篇: 在 WebApi 项目中快速开始使用 RabbitMQ

标签:
  • 热门焦点
  • 一加Ace2 Pro官宣:普及16G内存 引领24G

    一加Ace2 Pro官宣:普及16G内存 引领24G

    一加官方今天继续为本月发布的新机一加Ace2 Pro带来预热,公布了内存方面的信息。“淘汰 8GB ,12GB 起步,16GB 普及,24GB 引领,还有呢?#一加Ace2Pro#,2023 年 8 月,敬请期待。”同时
  • 俄罗斯:将审查iPhone等外国公司设备 保数据安全

    俄罗斯:将审查iPhone等外国公司设备 保数据安全

    iPhone和特斯拉都属于在各自领域领头羊的品牌,推出的产品也也都是数一数二的,但对于一些国家而言,它们的产品可靠性和安全性还是在限制范围内。近日,俄罗斯联邦通信、信息技术
  • 三言两语说透设计模式的艺术-简单工厂模式

    三言两语说透设计模式的艺术-简单工厂模式

    一、写在前面工厂模式是最常见的一种创建型设计模式,通常说的工厂模式指的是工厂方法模式,是使用频率最高的工厂模式。简单工厂模式又称为静态工厂方法模式,不属于GoF 23种设计
  • 一篇聊聊Go错误封装机制

    一篇聊聊Go错误封装机制

    %w 是用于错误包装(Error Wrapping)的格式化动词。它是用于 fmt.Errorf 和 fmt.Sprintf 函数中的一个特殊格式化动词,用于将一个错误(或其他可打印的值)包装在一个新的错误中。使
  • 如何使用JavaScript创建一只图像放大镜?

    如何使用JavaScript创建一只图像放大镜?

    译者 | 布加迪审校 | 重楼如果您曾经浏览过购物网站,可能遇到过图像放大功能。它可以让您放大图像的特定区域,以便浏览。结合这个小小的重要功能可以大大改善您网站的用户体验
  • 每天一道面试题-CPU伪共享

    每天一道面试题-CPU伪共享

    前言:了不起:又到了每天一到面试题的时候了!学弟,最近学习的怎么样啊 了不起学弟:最近学习的还不错,每天都在学习,每天都在进步! 了不起:那你最近学习的什么呢? 了不起学弟:最近在学习C
  • 年轻人的“职场羞耻感”,无处不在

    年轻人的“职场羞耻感”,无处不在

    作者:冯晓亭 陶 淘 李 欣 张 琳 马舒叶来源:燃次元&ldquo;人在职场,应该选择什么样的着装?&rdquo;近日,在网络上,一个与着装相关的帖子引发关注,在该帖子里,一位在高级写字楼亚洲金
  • 郭明錤称华为和江淮汽车合作开发问界MPV,定价100万左右、计划明年量产

    郭明錤称华为和江淮汽车合作开发问界MPV,定价100万左右、计划明年量产

    8 月 1 日消息,郭明錤今天在 Medium 平台发布博文,称华为正在和江淮汽车合作,开发售价在 100 万元的问界 MPV,预计在 2024 年第 2 季度量产,销量目标为
  • 三星Galaxy Z Fold/Flip 5国行售价曝光 :最低7499元/12999元起

    三星Galaxy Z Fold/Flip 5国行售价曝光 :最低7499元/12999元起

    据官方此前宣布,三星将于7月26日也就是明天在韩国首尔举办Unpacked活动,届时将带来带来包括Galaxy Buds 3、Galaxy Watch 6、Galaxy Tab S9、Galaxy
Top