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.每个码不允许重复: ...
随机推荐
- 几个Shell脚本的例子
[例子:001]判断输入为数字,字符或其他 #!/bin/bash read -p "Enter a number or string here:" input case $inp ...
- golang实现请求cloudflare修改域名A记录解析
现在有些DNS解析要收费,国内的几个厂商需要实名制.下面给出golang请求cloudflare修改域名A记录解析的代码. 准备工作: 在域名购买服务商处,将dns解析服务器改为cloudflare的 ...
- 华硕推出无风扇迷你电脑 PL64-明显是奔着软路由去的
看这个配置,做客厅软路由再合适不过了.要是针对客厅的影音需求,CPU性能以及对大容量存储的刚需,这个还是有些欠缺. IT之家 12 月 17 日消息,华硕 PL 系列迷你电脑现已迎来最新一代机型,其中 ...
- 保护IIS Web服务器安全的技巧
首先,开发一套安全策略 保护Web服务器的第一步是确保网络管理员清楚安全策略中的每一项制度.如果公司高层没有把服务器的安全看作是必须被保护的资产,那么保护工作是完全没有意义的.这项工作需要长期的努力. ...
- ZSTUOJ刷题⑩:Problem B.--零起点学算法103——查找最大元素
Problem B: 零起点学算法103--查找最大元素 Time Limit: 1 Sec Memory Limit: 64 MBSubmit: 9951 Solved: 4793 Descri ...
- shell相关基础面试题
用sed修改test.txt的23行test为tset: sed –i '23s/test/tset/g' test.txt 查看/web.log第25行第三列的内容. sed –n '25p' /w ...
- Idea提交文件时,添加不需要提交的文件至.gitignore文件中
1.在Idea中,依次打开File ---->Setting ---> Editor --->File Types 2.在当前编辑栏下方找到Ignore files and fold ...
- AX2012 查询用户在线操作记录
1 static void ExportSysClientAccessLog(Args _args) 2 { 3 SysClientAccessLog sysClientAccessLog; 4 5 ...
- 更多Linux实用命令
更多实用命令 进程相关 当程序运行在系统上时,我们称之为进程(process).想监测这些进程,需要熟悉 ps/top 等命令的用法.ps 命令好比工具中的瑞士军刀,它能输出运行在系统上的所有程序的许 ...
- git reset命令适用场景详解
☆ git reset 场景1:本地开发环境,已提交N个commit.但尚未push,希望:①丢弃本地所有的更改,代码强制回退到某个历史版本. 解决办法:git reset --hard HEAD~回 ...