题外话:为什么要hashcode进行spread? 充分使用key.hashCode()的高16位信息,保证hash分布更分散,

扩容操作是新建2倍于原表大小的新表,并将原表结点拷贝一份放在新表中,对原表无修改或修改很小。当原表所有结点都已被拷贝到新表中后,原表会被垃圾回收。

在jdk7中的HashMap实现类中,数组+链表。扩容操作是将原数组的结点一一进行hash计算,然后一一挂接到新数组上,所以不是基于复制结点的机制。
在jdk7中的ConcurrentHashMap实现类中,段(segment)+数组+链表。扩容操作是先遍历数组元素,在每个数组元素上遍历一遍链表,找到链表的最后n个结点(这n个结点在新数组一定属于同一个数组位置上),把这n个结点先挂接到新数组的数组位置上,这也叫lastRun机制。至于原数组的头结点到倒数n个结点之间的结点,再遍历一遍,通过复制每个结点的机制挂接到新数组上。

jdk8中的HashMap实现类中,数组+链表/红黑树。扩容操作是将原数组每个结点的hash值和原数组长度进行“与”操作,结果等于0代表该结点位置不变,落在新数组的同样位置,否则该结点在新数组的位置是[j + oldCap]上。
原因是:扩容是将数组长度扩大一倍,假如原长度是16(二进制是10000,掩码1111),新长度是32(二进制是100000,掩码11111),那么在计算结点所落的位置时,hash值原本是低4位参与计算,扩容后变成hash值低5位参与计算,这样的话,当参与运算的最高位也就是第五位,是1时,必然落在扩容后的新的位置,是0时,必然位置不变,因为原数组长度16的二进制第五位是1,所以通过将结点的hash值和原数组长度进行与操作,就可以知道结点在新数组中是保持相对不变还是落在高一点的位置上。

jdk8中的ConcurrentHashMap实现类中,数组+链表/红黑树。扩容操作是多个线程参与共同完成的,相比于jdk7版本的扩容,jdk8的扩容属于渐进式扩容,不是一蹴而就。将原数组长度为n作为扩容任务的总数,切分成m块作为m个小任务,每个小任务有且只有一个线程来负责完成扩容(因为扩容后的数组长度是原来的2倍,结点要么在新数组的相对原位置i,要么在i+OldTableSize处,所以其他线程在扩容别的小任务时,不会和当前线程存在位置冲突)。对于扩容时,链表同样先找lastRun然后挂接到新数组上,前面的结点再通过复制的机制挂接到新数组上。

HashMap并发问题:死循环的原因
Hashmap的Resize包含扩容和ReHash两个步骤,ReHash在并发的情况下可能会形成链表环。因为,链表采用头插法,将原数组转移到新数组时,会从前向后遍历链表结点,头插法机制恰好使新数组中结点的相对顺序和原数组中颠倒过来。在并发的时候,假如原来的结点顺序被线程A颠倒了,而被挂起的线程b在恢复执行后,拿扩容前的节点和顺序继续完成第一次循环,而后又遵循A线程扩容后的链表顺序重新排列链表中的顺序,即又颠倒了一下顺序,最终形成了环。

jdk7和8中关于HashMap和concurrentHashMap的扩容过程总结,以及HashMap死循环的更多相关文章

  1. 沉淀再出发:java中的HashMap、ConcurrentHashMap和Hashtable的认识

    沉淀再出发:java中的HashMap.ConcurrentHashMap和Hashtable的认识 一.前言 很多知识在学习或者使用了之后总是会忘记的,但是如果把这些只是背后的原理理解了,并且记忆下 ...

  2. 调试JDK源代码-一步一步看HashMap怎么Hash和扩容

    调试JDK源代码-一步一步看HashMap怎么Hash和扩容 调试JDK源代码-ConcurrentHashMap实现原理 调试JDK源代码-HashSet实现原理 调试JDK源代码-调试JDK源代码 ...

  3. HashMap 什么时候进行扩容呢

    HashMap扩容: 当HashMap中的元素越来越多的时候,碰撞的几率也就越来越高(因为数组的长度是固定的),所以为了提高查询的效率,就要对HashMap的数组进行扩容,数组扩容这个操作也会出现在A ...

  4. Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析

    Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析 今天发一篇”水文”,可能很多读者都会表示不理解,不过我想把它作为并发序列文章中不可缺少的一块来介绍.本来以为花不了 ...

  5. Java中关于Map的使用(HashMap、ConcurrentHashMap)

    在日常开发中Map可能是Java集合框架中最常用的一个类了,当我们常规使用HashMap时可能会经常看到以下这种代码: Map<Integer, String> hashMap = new ...

  6. Java7/8 中 HashMap 和 ConcurrentHashMap的对比和分析

    大家可能平时用HashMap比较多,相对于ConcurrentHashMap 来说并不是很熟悉.ConcurrentHashMap 是 JDK 1.5 添加的新集合,用来保证线程安全性,提升 Map ...

  7. JDK7与JDK8中HashMap的实现

    JDK7中的HashMap HashMap底层维护一个数组,数组中的每一项都是一个Entry transient Entry<K,V>[] table; 我们向 HashMap 中所放置的 ...

  8. java7,java8 中HashMap和ConcurrentHashMap简介

    一:Java7 中的HashMap 结构: HashMap 里面是一个数组,然后数组中每个元素是一个单向链表.链表中每个元素称为一个Entry 实例,Entry 包含四个属性:key, value, ...

  9. Java7与Java8中的HashMap和ConcurrentHashMap知识点总结

    JAVA7 Java7的ConcurrentHashMap里有多把锁,每一把锁用于其中一部分数据,那么当多线程访问容器里不同数据段的数据时,线程间就不会存在锁竞争,从而可以有效的提高并发访问效率呢.这 ...

随机推荐

  1. 内存溢出OOM

    如何避免OOM 异常? 想要避免OOM 异常首先我们要知道什么情况下会导致OOM 异常. 1.图片过大导致OOM Android 中用bitmap 时很容易内存溢出,比如报如下错误:Java.lang ...

  2. iPhone 系统刷机

    1. 下载好固件(爱思 或者 pp助手) e.g. http://jailbreak.25pp.com/gujian/ 2. 将电脑与手机连接上,弹出iTunes软件即可 3. 长按手机电源键 关闭手 ...

  3. [洛谷P1006] 传纸条

    双线程DP的常识:DP的阶段问题:多阶段决策问题 传送门:$>here<$ 题意 n*m的矩阵里,从左上角走到右下角(只能往右或往下),再从右下角走回左上角(只能往左或往上).其中不能重复 ...

  4. 2059 - Authentication plugin 'caching_sha2_password' cannot be loaded: dlopen(../Frameworks/caching_sha2_password.so, 2): image not found

    mac本地安装mysql后,navicat连接报错: - Authentication plugin ): image not found 解决方法 在控制台登陆后重新改下密码即可 ALTER USE ...

  5. 分布式版本控制系统 Git 的安装与使用

    作业的要求来自于:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/2097 远端库地址:https://github.com/CJL29 ...

  6. 深入剖析Kubernetes学习笔记:容器基础(05-06)

    05 :从进程说起 1.容器本身没有价值,有价值的是"容器编排" 2.什么是进程? 一旦"程序"被执行起来,它就从磁盘上的二进制文件,变成 1.计算机内存中的数 ...

  7. Maven(一)简介安装

    一.什么是maven,它能干什么? ①:maven maven是一个项目管理工具.它包含了一个项目对象模型,一组标准集合,一个生命周期,一个依赖管理系统,和用来运行定义生命周期中插件目标的逻辑. 传统 ...

  8. DirectX11--ComPtr智能指针

    综述 DirectX11 With Windows SDK完整目录 欢迎加入QQ群: 727623616 可以一起探讨DX11,以及有什么问题也可以在这里汇报. IUnknown接口类 DirectX ...

  9. Spring rabbitMq 中 correlationId或CorrelationIdString 消费者获取为null的问题

    问题 在用Spring boot 的 spring-boot-starter-amqp   快速启动 rabbitMq 是遇到了个坑 消费者端获取不到:correlationId或Correlatio ...

  10. 01.QT初学--两个窗口相互切换

    //qqwidget.cpp #include "qqwidget.h" #include "ui_qqwidget.h" qqwidget::qqwidget ...