介绍

HashMap实现原理

之前的文章已经分析了HashMap在JDK1.7的实现,这篇文章就只分析HashMap死循环形成的原因

死循环形成是在扩容转移元素的时候发生的

void resize(int newCapacity) {
Entry[] oldTable = table;
int oldCapacity = oldTable.length;
if (oldCapacity == MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return;
} Entry[] newTable = new Entry[newCapacity];
transfer(newTable, initHashSeedAsNeeded(newCapacity));
table = newTable;
threshold = (int)Math.min(newCapacity * loadFactor, MAXIMUM_CAPACITY + 1);
}

发生的具体时机在transfer函数中,默认情况下rehash为false

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;
}
}
}

正常的transfer过程

例子不考虑扩容阈值,假设放4个元素时开始扩容



主要有2个有意思的地方

  1. 原来在oldTable[i]位置的元素,会被放到newTable[i]或者newTable[i+oldTable.length]的位置
  2. 链表在复制的时候会反转

并发下异常的transfer

假设线程1执行完Entry<K,V> next = e.next后被挂起,此时e指向key3,next指向key7

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; // 线程1执行完这一句被挂起
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;
}
}
}



线程2也来执行transfer函数,并执行完成,此时的状态为



此时线程1接着执行余下的代码,将key3放到线程1的table[3]处



接着将e指向key7,不为null,再次进入循环,将next指向key3如下图



当跑完这次循环时key7被放入线程1的table中,e指向key3,next指向null



e不为null,还能再次执行循环,key3再次插入线程1中table[3]的头节点,此时e变为null,循环完毕。结构如下



环形链表形成,此时无论将线程1还是线程2的table设置为newTable,当调用get方法执行到这条链上时,死循环形成

欢迎关注

参考博客

[1]https://juejin.im/post/5a66a08d5188253dc3321da0

[2]https://www.javashitang.com/?p=1033

[3]https://coolshell.cn/articles/9606.html

面试官:HashMap死循环形成的原因是什么?的更多相关文章

  1. 一个HashMap能跟面试官扯上半个小时

    一个HashMap能跟面试官扯上半个小时 <安琪拉与面试官二三事>系列文章 一个HashMap能跟面试官扯上半个小时 一个synchronized跟面试官扯了半个小时 一个volatile ...

  2. 面试高峰期,如何应对面试官的jvm刁难,特写一篇jvm面经(第一部)

    已经进入三月份,正所谓金三银四,正是一年最好的招聘期,想必我的公号粉丝们一定有不少想要跳槽的吧,哈哈,/**偷偷告诉你们其实小编也准备跳槽*/(我要加个注释,被老板知道可就完蛋了),说到面试,想必大家 ...

  3. 面试官问:HashMap在并发情况下为什么造成死循环?一脸懵

    这个问题是在面试时常问的几个问题,一般在问这个问题之前会问Hashmap和HashTable的区别?面试者一般会回答:hashtable是线程安全的,hashmap是线程不安全的. 那么面试官就会紧接 ...

  4. 面试官再问你 HashMap 底层原理,就把这篇文章甩给他看

    前言 HashMap 源码和底层原理在现在面试中是必问的.因此,我们非常有必要搞清楚它的底层实现和思想,才能在面试中对答如流,跟面试官大战三百回合.文章较长,介绍了很多原理性的问题,希望对你有所帮助~ ...

  5. 我说HashMap初始容量是16,面试官让我回去等通知

    众所周知HashMap是工作和面试中最常遇到的数据类型,但很多人对HashMap的知识止步于会用的程度,对它的底层实现原理一知半解,了解过很多HashMap的知识点,却都是散乱不成体系,今天一灯带你一 ...

  6. HashMap闭环(死循环)的详细原因(转)

    为何出现死循环简要说明 HashMap是非线程安全的,在并发场景中如果不保持足够的同步,就有可能在执行HashMap.get时进入死循环,将CPU的消耗到100%. HashMap采用链表解决Hash ...

  7. 面试28k职位,老乡面试官从HashCode到HashMap给我讲了一下午!「回家赶忙整理出1.6万字的面试材料」

    作者:小傅哥 博客:https://bugstack.cn 目录 一.前言 二.HashCode为什么使用31作为乘数 1. 固定乘积31在这用到了 2. 来自stackoverflow的回答 3. ...

  8. 阿里面试官:HashMap 熟悉吧?好的,那就来聊聊 Redis 字典吧!

    最近,小黑哥的一个朋友出去面试,回来跟小黑哥抱怨,面试官不按套路出牌,直接打乱了他的节奏. 事情是这样的,前面面试问了几个 Java 的相关问题,我朋友回答还不错,接下来面试官就问了一句:看来 Jav ...

  9. 阿里面试官用HashMap把我问倒了

    本人是一名大三学生,最近在找暑期实习,其中也面试过两次阿里,一次菜鸟网络部门.一次网商银行部门,当然我都失败了,同时也让我印象很深刻,因此记录了其中一些面试心得,我觉得这个问题很值得分享,因此分享给大 ...

随机推荐

  1. android优化中国风应用、完整NBA客户端、动态积分效果、文件传输、小说阅读器等源码

    Android精选源码 android拖拽下拉关闭效果源码 一款优雅的中国风Android App源码 EasySignSeekBar一个漂亮而强大的自定义view15 android仿蘑菇街,蜜芽宝 ...

  2. FPGA实现CRC编码

    首先CRC应用的主要场景: 在数据通信中要求数据的高度可靠性,但实际上由于信道不理想或者噪声干扰都会导致数据的误码率 那么对于信道不理想产生的影响可以用均衡的方法进行改善或者消除,而噪声干扰的数据误码 ...

  3. 详解JavaScript Document对象

    转自:http://segmentfault.com/a/1190000000660947 在浏览器中,与用户进行数据交换都是通过客户端的javascript代码来实现的,而完成这些交互工作大多数是d ...

  4. 10X genomics|cell base|in-vivo based|model organisms|SBI|

    生命组学-药物基因组学 精准医学的内容有个人全基因组测序,移动可穿戴设备,它可以实时监测,深度学习模型预测疾病,对疾病预测做到有效.安全和可控. 药物基因组学就是研究疾病.化合物和靶点之间的关系,关键 ...

  5. Python---8函数(函数的参数&递归函数)

    一.函数的参数 Python的函数定义非常简单,但灵活度却非常大.除了正常定义的必选参数外,还可以使用默认参数.可变参数和关键字参数,使得函数定义出来的接口,不但能处理复杂的参数,还可以简化调用者的代 ...

  6. leetcode第23题:合并K个排序链表

    首先我想到的是采用一般递归法,将K个链表合并化为(k-1)两个链表合并 class Solution: def mergeKLists(self, lists: List[ListNode]) -&g ...

  7. MyBatis学习笔记二:MyBatis生产中使用环境搭建

    这里是在上一个环境的基础上修改的,这里就不在给出所有的配置,只给出哪里修改的配置 1.修改POJO对象为注解方式 2.创建Dao层接口 package com.orange.dao; import c ...

  8. python 添加字符串的七种方法

    #使用{}的方法 s1 = 'Hello {}! My name is {}.'.format('World', 'Python猫') print(s1) s2 = 'Hello {0} My nam ...

  9. OSCACHE介绍

    Cache是一种用于提高系统响应速度.改善系统运行性能的技术.尤其是在Web应用中,通过缓存页面的输出结果,可以很显著的改善系统运行性能.本文中作者给大家介绍一个实现J2EE框架中Web应用层缓存功能 ...

  10. container/injection简介以及发展历史

    一:什么是Container?Container的作用? 容器是一个标准的软件单元,它将代码及其所有依赖关系打包,以便应用程序从一个计算环境快速可靠地运行到另一个计算环境.container的主要作用 ...