JDK 7 HashMap 并发情况下的死锁问题
问题描述
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 并发情况下的死锁问题的更多相关文章
- 并发情况下synchronized死锁
存在缺陷的代码: public class DataPropertyIdAndNameRepositoryImpl{ /** 发布标志 */ private volatile boolean publ ...
- 面试官问:HashMap在并发情况下为什么造成死循环?一脸懵
这个问题是在面试时常问的几个问题,一般在问这个问题之前会问Hashmap和HashTable的区别?面试者一般会回答:hashtable是线程安全的,hashmap是线程不安全的. 那么面试官就会紧接 ...
- PHP通过加锁实现并发情况下抢码实现
需求:抢码功能 要求: 1.特定时间段才开放抢码: 2.每个时间段放开的码是有限的: 3.每个码不允许重复: 实现: 1.在不考虑并发的情况下实现: function get_code($len){ ...
- 关于WCF服务在高并发情况下报目标积极拒绝的异常处理
最近弄了个wcf的监控服务,偶尔监控到目标服务会报一个目标积极拒绝的错误.一开始以为服务停止了,上服务器检查目标服务好好的活着.于是开始查原因. 一般来说目标积极拒绝(TCP 10061)的异常主要是 ...
- 解决并发情况下库存减为负数问题--update2016.04.24
场景: 一个商品有库存,下单时先检查库存,如果>0,把库存-1然后下单,如果<=0,则不能下单,事务包含两条sql语句: ; update products ) WHERE id=; 在并 ...
- WCF服务在高并发情况下报目标积极拒绝的异常处理 z
http://www.cnblogs.com/kklldog/p/5037006.html wcf的监控服务,偶尔监控到目标服务会报一个目标积极拒绝的错误.一开始以为服务停止了,上服务器检查目标服务好 ...
- Jackson高并发情况下,产生阻塞
情况:在高并发情况下,查看线程栈信息,有大量的线程BLOCKED. 从线程栈得知,线程栈中出现了阻塞,锁在了com.fasterxml.jackson.databind.ser.SerializerC ...
- Linux的虚拟内存管理-如何分配和释放内存,以提高服务器在高并发情况下的性能,从而降低了系统的负载
Linux的虚拟内存管理有几个关键概念: Linux 虚拟地址空间如何分布?malloc和free是如何分配和释放内存?如何查看堆内内存的碎片情况?既然堆内内存brk和sbrk不能直接释放,为什么不全 ...
- 高并发情况下分布式全局ID
1.高并发情况下,生成分布式全局id策略2.利用全球唯一UUID生成订单号优缺点3.基于数据库自增或者序列生成订单号4.数据库集群如何考虑数据库自增唯一性5.基于Redis生成生成全局id策略6.Tw ...
- PHP通过加锁实现并发情况下抢码功能
本文基于php语言使用加锁实现并发情况下抢码功能,特定时间段开放抢码并不允许开放的码重复: 需求:抢码功能 要求: 1.特定时间段才开放抢码: 2.每个时间段放开的码是有限的: 3.每个码不允许重复: ...
随机推荐
- Python 字典类型
1.由于字典中的 key 是非常关键的数据,而且程序需要通过 key 来访问 value,因此字典中的 key 不允许重复.程序既可使用花括号语法来创建字典,也可使用 dict() 函数来创建字典.实 ...
- 杭电oj 平方和与立方和
给定一段连续的整数,求出他们中所有偶数的平方和以及所有奇数的立方和. Input 输入数据包含多组测试实例,每组测试实例包含一行,由两个整数m和n组成. Output 对于每组输入数据,输出一 ...
- (Jmeter笔记)jmeter连接数据库(mysql)
下载mysql连接驱动 地址:https://dev.mysql.com/downloads/connector/j/ ****把mysql连接驱动放在Jmeter/lib目录下**** >&g ...
- 第九章 MySQL 高可用(MHA)
MySQL 高可用(MHA) 一 MHA高可用部署 需要使用的前提: 当普通主从复制不能满足我们的需求, 主节点宕机 影响业务的不间断运行.这里就需要用到MHA 高可用 1. MHA高可用的介绍 ...
- Android studio学习第二期
layout目录下app页面布局文件 activity_main.xml的创建和跳转 activity为一个应用程序组件,提供一个屏幕,用户可以用来交互为了完成某项任务 创建步骤 这里选择第二个xml ...
- Tomcat9启动闪退或者在windows服务中启动异常以及启动日志乱码问题
首先虽然jdk6以后不需要在环境变量中额外配置jre了,但是我在tomcat的bin下startup.bat时启动时发现 可见用到了JRE_HOME,所以你需要去额外配置一下,否则会出现另外一种错误, ...
- linux虚拟机,ifconfig无法获取静态ip地址
之前一直显示这种ip地址,如下图(网图),查看了DHCP,是正常启动的,虚拟网络编辑器中设置的也正确.后来发现更改虚拟机的设置后就可以了,如下: 设置方法:VMware-虚拟机-设置-网络适配器,选择 ...
- 在Unity3D中开发的Toon Shader
SwordMaster Toon Shader 特点 此卡通渲染风格的Shader是顶点片元Shader,由本人手动编写完成 此卡通渲染风格的Shader已经在移动设备真机上进行过测试,可以直接应用到 ...
- C# 使用Enumerable.Range 打印数字
static void Main(string[] args) { var list1 = Enumerable.Range(0, (int)Math.Pow(2, 22)).ToList(); va ...
- [杂谈吐槽]UE国内社区环境
此篇博客是我个人想法,当然也是不争的事实,如果您有意见,那您也是我说那些人其中的一员. --此部分为社区环境差最恶劣的原因-- 国内的虚幻社区环境可以说不能再烂了,虚幻商城和虚幻引擎的蓝图是非常强大的 ...