面试官问:HashMap在并发情况下为什么造成死循环?一脸懵
这个问题是在面试时常问的几个问题,一般在问这个问题之前会问Hashmap和HashTable的区别?面试者一般会回答:hashtable是线程安全的,hashmap是线程不安全的。
那么面试官就会紧接着问道,为什么hashmap不是线程安全的,会造成什么问题么?于是面试者就回答:HashMap在并发情况下的put操作会造成死循环。
这时候就会被面试官问:HashMap在并发为什么造成死循环?
很多面试者这时候就会一脸懵。没有过相关经验和深入的理解源码是很难回答这个问题的。
下面我们就通过HahMap源码来验证下,多线程并发put操作为何会生成环形链表,产生死循环。
这是HashMap扩容的源码
/**
* Transfers all entries from current table to newTable.
*/
void transfer(Entry[] newTable, boolean rehash) {
int newCapacity = newTable.length;
for (Entry<K,V> e : table) {
while(null != e) {
//(关键代码)
Entry<K,V> next = e.next;
if (rehash) {
e.hash = null == e.key ? 0 : hash(e.key);
}
int i = indexFor(e.hash, newCapacity);
e.next = newTable[i];
newTable[i] = e;
e = next;
} // while
}
}
开始之前先回顾一下HashMap的扩容机制:
HashMap默认设定的装载因子为0.75(可改),HashMap的大小为length,已经装载的元素数量为num,当( num / length )> 装载因子时,
开始扩容
先创建一个散列表HashMap:Map<Integer> map = new HashMap<Integer>(2);
,装载因子默认0.75,当插入第二个元素时,会发生扩容
我们先在map中放入6、8两个元素。
这时有两个线程都执行put操作,那么在此刻两个线程都对HashMap进行扩容,这时候就注意在上文的源码里注释为(关键代码)这一行:Entry<K,V> next = e.next;
假如两个线程分别为A、B两个线程。A线程在执行到关键代码
这一行线程就被挂起,那么此刻A线程中:e = 6; next = 8;
接着B线程开始进行扩容,假设新的散列表中,节点6 和 节点8 还是会产生散列冲突,那么线程B的扩容过程为:
先申请一个空间为旧散列表两倍大的空间
将节点6 迁移至新散列表
将节点8 迁移至新散列表
此时线程B的扩容已经完成,节点8 的后继节点为节点6 ,节点6的后继节点为null。
我们将新旧两个散列表做个对比:
回顾一下线程A的当前状态:e = 6; next = 8;
,处于挂起状态。接着A线程取消挂起状态,接着执行(关键代码)之后的代码:将e = 6;
节点迁移至新的散列表,并将next = 8
的节点赋值给e
。扩容并迁移节点6后的状态,如下图所示:
于是第二次执行while循环时,当前待处理节点:e = 8;
在执行(关键代码)这一行时,由于线程B在扩容时将节点8的后继节点变为节点6,所以next不是为null,而是next = 6;
接着开始执行第三次while循环,由于节点6的后继节点为null,所以 next = null;
,执行完第三次while循环的结果为:
循环结束。
可以看到扩容后的散列表中链表成环,如果这时候执行get()
方法查询,就会导致死循环。
总结
HashMap的方法不是线程安全的。HashMap在并发执行put操作时发生扩容,可能会导致节点丢失,产生环形链表等情况。
- 节点丢失,会导致数据不准
- 生成环形链表,会导致get()方法死循环。
知识拓展
在jdk1.7中,由于扩容时使用头插法,在并发时可能会形成环状列表,导致死循环,在jdk1.8中改为尾插法,可以避免这种问题,但是依然避免不了节点丢失的问题。
建议
HashMap的设计初衷就不是在并发情况下使用,如果有并发的场景,推荐使用ConcurrentHashMap
面试官问:HashMap在并发情况下为什么造成死循环?一脸懵的更多相关文章
- 2020-04-22:谈谈JDK1.8下的HashMap在并发情况下链表成环的过程。(挖)
福哥答案2020-04-22: jdk1.8下的hashmap采用的是尾插法,不会有链表成环的问题.jdk1.7下采用的头插***有链表成环的问题. hashmap成环原因的代码出现在transfer ...
- 面试官问我,Redis分布式锁如何续期?懵了。
前言 上一篇[面试官问我,使用Dubbo有没有遇到一些坑?我笑了.]之后,又有一位粉丝和我说在面试过程中被虐了.鉴于这位粉丝是之前肥朝的粉丝,而且周一又要开启新一轮的面试,为了回馈他长期以来的支持,所 ...
- 面试官问线程安全的List,看完再也不怕了!
最近在Java技术栈知识星球里面有球友问到了线程安全的 List: 扫码查看答案或加入知识星球 栈长在之前的文章<出场率比较高的一道多线程安全面试题>里面讲过 ArrayList 的不安全 ...
- 【原创】面试官问我G1回收器怎么知道你是什么时候的垃圾?
这是why技术的第36篇原创文章 上面的图片是我上周末在家拍的.以后的文章里面我的第一张配图都用自己随手拍下的照片吧.分享生活,分享技术,哈哈. 阳台上的花开了,成都的春天快来了,疫情也应该快要过去了 ...
- [每日一题]面试官问:Async/Await 如何通过同步的方式实现异步?
关注「松宝写代码」,精选好文,每日一题 时间永远是自己的 每分每秒也都是为自己的将来铺垫和增值 作者:saucxs | songEagle 一.前言 2020.12.23 日刚立的 flag,每日一 ...
- Java之HashMap在多线程情况下导致死循环的问题
PS:不得不说Java编程思想这本书是真心强大.. 学习内容: 1.HashMap<K,V>在多线程的情况下出现的死循环现象 当初学Java的时候只是知道HashMap<K,V& ...
- 面试必问---HashMap原理分析
一.HashMap的原理 众所周知,HashMap是用来存储Key-Value键值对的一种集合,这个键值对也叫做Entry,而每个Entry都是存储在数组当中,因此这个数组就是HashMap的主干.H ...
- 面试官问:JS的this指向
前言 面试官出很多考题,基本都会变着方式来考察this指向,看候选人对JS基础知识是否扎实.读者可以先拉到底部看总结,再谷歌(或各技术平台)搜索几篇类似文章,看笔者写的文章和别人有什么不同(欢迎在评论 ...
- 当面试官问我ArrayList和LinkedList哪个更占空间时,我这么答让他眼前一亮
前言 今天介绍一下Java的两个集合类,ArrayList和LinkedList,这两个集合的知识点几乎可以说面试必问的. 对于这两个集合类,相信大家都不陌生,ArrayList可以说是日常开发中用的 ...
随机推荐
- Java面试知识点1
typora-root-url: ......\Software\Typora\Picture Bean的作用域 在Spring的元素的scope属性设置bean的作用域,用来决定bean是单实例还是 ...
- FTP服务端 FTP服务端搭建教程
FTP服务端搭建教程如下:一.需要准备以下工具:1.微型FTP服务端.2.服务器管理工具二.操作步骤:1.下载微型FTP服务端.(站长工具包可下载:http://zzgjb.iis7.com/ )2. ...
- Object类:又回到最初的起点
Object类大概是每个JAVA程序员认识的第一个类,因为它是所有其他类的祖先类.在JAVA单根继承的体系下,这个类中的每个方法都显得尤为重要,因为每个类都能够调用或者重写这些方法.当你JAVA学到一 ...
- Shell学习(四)Shell运算符
一.基础运算 原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如 awk 和 expr,expr 最常用. expr 是一款表达式计算工具,使用它能完成表达式的求值操作. #计算两个数 ...
- (最新 9000 字 )Spring Boot 配置特性解析
爱生活,爱编码,微信搜一搜[架构技术专栏]关注这个喜欢分享的地方.本文 架构技术专栏 已收录,有各种JVM.多线程.源码视频.资料以及技术文章等你来拿 一.概述 目前Spring Boot版本: 2. ...
- Mac 环境下配置 MySQL 以及 Mac终端登录MySQL
1.首先mysql官网下载Mac 版 mysql直接安装 2.打开偏好设置-> MySQL -> 查看是否开启mysql服务 3.打开终端 进入mysql目录: /usr/local/my ...
- (转载)Altium Designer 17 (AD17)
转载自:http://blog.csdn.net/qq_29350001/article/details/52199356 以前是使用DXP2004来画图的,后来转行.想来已经有一年半的时间没有画过了 ...
- JUC 常用4大并发工具类
什么是JUC? JUC就是java.util.concurrent包,这个包俗称JUC,里面都是解决并发问题的一些东西 该包的位置位于java下面的rt.jar包下面 4大常用并发工具类: Count ...
- 消息队列MQ面试专题(rabbitmq)
正文: 1.什么是 rabbitmq 采用 AMQP 高级消息队列协议的一种消息队列技术,最大的特点就是消费并不需要确保提供方存在,实现了服务之间的高度解耦 2.为什么要使用 rabbitmq 在分布 ...
- Hibernate4.3 继承映射
一.单表继承映射 父子类合成一张表 An_id An_name gender Weight Height type 1 dog 1 300 D 2 cat 1 100 C 在Animal.hbm.xm ...