问题描述

JDK7的 HashMap 解决冲突用的是链表,在插入链表的时候用的是头插法,每次在链表的头部插入新元素。resize() 的时候用的依然是头插,头插的话,如果某个下标中的链表在新的 table 中依然索引到同一个下标中,那么原链表的顺序会反转。因为链表是顺序访问的,那么每次访问一个节点,会把当前节点插到新 table 链表的头部,这样原链表的最后一个元素在 resize() 后,就变成新链表的头部了(如果它们索引到新 table 的同一个下标中)。这在并发的情况下可能产生环。

详细解释

resize()的代码

 for (Entry<K,V> e : table) { // e 是每一个链表的头节点
while(null != e) {
Entry<K,V> next = e.next; // 当前节点 e 的下一个节点 next
int i = indexFor(e.hash, newCapacity); // i 是 e 在新 table 中的索引
e.next = newTable[i]; // 头插法,当前节点的 next 是当前新 table 对应索引的头节点
newTable[i] = e; // 更新 新 table 对应索引的头节点
e = next; // 旧 table 当前链表的下一个节点
}
}

​ map 当前处于扩容边缘,再添加一个 Entry 就得扩容。现在有两个线程,Thread1 要 put,Thread2 也要 put,那么如果没有锁,就可能会出现环。

Thread1 先扩容,执行到 e=e0;next=e1; 的时候,Thread2 开始执行扩容,Thread2 完成扩容之后,Thread1 继续执行,即下图中的前两格。那么当前出现了一个现象,e1 的 next 变成 e0 了,e0 的 next 变成 null 了。

​ 然后 Thread1 继续执行,e0 的 next 变成 null,newTable1[i]=e0; 并且此时 e1 指向 e0。next 没有变,还是最开始指向的 next=e1;

继续下一次循环,这时 e=e1; 重点 :next=e0;,继续执行,可以得到 e1 指向 e0,newTable1[i]=e1; 的结果,如果不继续循环这就是对的,但是 此时 next=e0;。

总结

会出现环就是因为头插在扩容的时候会反转原链表,使得有出现环的可能。换成尾插,原来是什么顺序,扩容之后还是什么顺序,就不会出现一个线程抢先之后 e1 指向 e0 的情况,依旧时 e0 指向 e1,就不会出现环。

即使 JDK8 改成 尾插,但是并发情况下,同时修改同一个 key 的值 或者 同时删除+修改同一个 key 等都会出现其他并发问题,所以并发情况下不要用 HashMap,建议用带锁的 ConcurrentHashMap。

JDK 7 HashMap 并发情况下的死锁问题的更多相关文章

  1. 并发情况下synchronized死锁

    存在缺陷的代码: public class DataPropertyIdAndNameRepositoryImpl{ /** 发布标志 */ private volatile boolean publ ...

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

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

  3. PHP通过加锁实现并发情况下抢码实现

    需求:抢码功能 要求: 1.特定时间段才开放抢码: 2.每个时间段放开的码是有限的: 3.每个码不允许重复: 实现: 1.在不考虑并发的情况下实现: function get_code($len){ ...

  4. 关于WCF服务在高并发情况下报目标积极拒绝的异常处理

    最近弄了个wcf的监控服务,偶尔监控到目标服务会报一个目标积极拒绝的错误.一开始以为服务停止了,上服务器检查目标服务好好的活着.于是开始查原因. 一般来说目标积极拒绝(TCP 10061)的异常主要是 ...

  5. 解决并发情况下库存减为负数问题--update2016.04.24

    场景: 一个商品有库存,下单时先检查库存,如果>0,把库存-1然后下单,如果<=0,则不能下单,事务包含两条sql语句: ; update products ) WHERE id=; 在并 ...

  6. WCF服务在高并发情况下报目标积极拒绝的异常处理 z

    http://www.cnblogs.com/kklldog/p/5037006.html wcf的监控服务,偶尔监控到目标服务会报一个目标积极拒绝的错误.一开始以为服务停止了,上服务器检查目标服务好 ...

  7. Jackson高并发情况下,产生阻塞

    情况:在高并发情况下,查看线程栈信息,有大量的线程BLOCKED. 从线程栈得知,线程栈中出现了阻塞,锁在了com.fasterxml.jackson.databind.ser.SerializerC ...

  8. Linux的虚拟内存管理-如何分配和释放内存,以提高服务器在高并发情况下的性能,从而降低了系统的负载

    Linux的虚拟内存管理有几个关键概念: Linux 虚拟地址空间如何分布?malloc和free是如何分配和释放内存?如何查看堆内内存的碎片情况?既然堆内内存brk和sbrk不能直接释放,为什么不全 ...

  9. 高并发情况下分布式全局ID

    1.高并发情况下,生成分布式全局id策略2.利用全球唯一UUID生成订单号优缺点3.基于数据库自增或者序列生成订单号4.数据库集群如何考虑数据库自增唯一性5.基于Redis生成生成全局id策略6.Tw ...

  10. PHP通过加锁实现并发情况下抢码功能

    本文基于php语言使用加锁实现并发情况下抢码功能,特定时间段开放抢码并不允许开放的码重复: 需求:抢码功能 要求: 1.特定时间段才开放抢码: 2.每个时间段放开的码是有限的: 3.每个码不允许重复: ...

随机推荐

  1. python菜鸟学习: 9. 文件操作

    # -*- coding: utf-8 -*-import sys, time# 读文件:一次性读取所有内容#r=readf = open("singe.txt", 'r', en ...

  2. CF1561D Up the Strip

    Up the Strip 题意 你现在在 \(n\) 号格子,你需要跳到 \(1\) 号格子,你可以有两种跳法: 你可以做减法,即选择一个数 \(k\in [1,n)\) ,从 \(n\) 跳到 \( ...

  3. noi 1.1 5 输出保留12位小数的浮点数

    描述 读入一个双精度浮点数,保留12位小数,输出这个浮点数. 输入 只有一行,一个双精度浮点数. 输出 也只有一行,保留12位小数的浮点数. 样例输入 3.1415926535798932 样例输出 ...

  4. 杭电oj--1019题C++实现

    这道题有两个问题: 首先,是求利用数论的辗转相除法求最大公约数,后再求最小公倍数m*n/gcd(m,n),其中,m*n可能会超过int 数据范围,所以,该语句换成m/gcd(m,n)*n. 然后是如果 ...

  5. 比较有趣的C语言小程序

    1.判断是否是闰年: #include <stdio.h> int main(void) {     int year, a;     printf("Please enter  ...

  6. textarea兼容问题

    一.IOS 中不允许输入 <textarea contenteditable="true"></textarea> textarea { -webkit-u ...

  7. leetcode-560-和为 K 的子数组

    给你一个整数数组 nums 和一个整数 k ,请你统计并返回 该数组中和为 k 的连续子数组的个数 . 示例 1: 输入:nums = [1,1,1], k = 2 输出:2 示例 2: 输入:num ...

  8. mysql自动生成时间

    字段类型: DATETIME 默认值: CURRENT_TIMESTAMP

  9. 记录jupyter lab 多个kernel混乱的问题

    问题描述 在Anaconda下我有多个虚拟环境,其中一个叫d2l,由于pytorch版本和cuda算力不匹配,重新create了一个环境:d2l_new.然后环境配置好了之后激活环境,启动jupyte ...

  10. ucharts的区域图、折线图(有x轴的),修改x轴显示为隔一个显示

    1.原本的显示方式: 2.想要的效果: 3.这边我使用的是uchart的组件,在uni_modules > qiun-data-charts > js_sdk > u-charts, ...