热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

HashMap在多线程环境下偶然造成InfiniteLoop导致程序宕机

在多线程环境下,非线程安全的hashmap可能会造成的问题packagelittlehow.map;importorg.junit.After;importorg.junit.Before;im

在多线程环境下,非线程安全的hashmap可能会造成的问题


package littlehow.map;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
* HashMapInfiniteLoop hashmap死循环造成的cpu 100%
* 有时候,会出现很奇怪的现象,那就是程序运行一段时间会出现宕机,重启之后就没事儿了
* 具体什么原因也很难查找。
* 在高并发环境下,因为hashmap的线程不安全性,可能会引起上述现象
* 现在就看看,这种现象如何发生的
*
* @author littlehow
* @time 2016-07-11 10:16
*/
public class HashMapInfiniteLoop {
//初始长度为4的hashmap
private Map, String> map = new HashMap, String>(4);
//线程数量
final int count = 200;
final CountDownLatch countDownLatch = new CountDownLatch(count);
@Before
public void init() {
//因为hash计算结果类似于mod,所以我们可以事先准备冲突的hash对
//rehash的源码,可以看出当size==threshold也就是4的时候会进行resize,
//从而重新分布元素
/** if ((size >= threshold) && (null != table[bucketIndex])) {
resize(2 * table.length);
hash = (null != key) ? hash(key) : 0;
bucketIndex = indexFor(hash, table.length);
}

for (Entry,V> e : table) {
while(null != e) {
Entry,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;
}
}
*/
// 3 11 7 15 put后这三个都出现了hash冲突,所以结构为 3 -> 11 -> 7 -> 15 的链表
//当再put19时,又出现冲突, 这时候就需要扩容。
// 正常情况形成两个链表 11 -> 3 -> 19 和 15 -> 7
//但是当执行线程以执行到如 Entry next = e.next;获取到的next=11时线程被挂起;
//线程二来执行成功,线程一继续,e=7,next=15,进行rehash,执行到
//newTable[i] = e = 7; e = next = 15,而线程二已经排好 15 -> 7,
//很明显线程一形成的链表为7 -> 15,合并结果就是 15 -> 7 -> 15形成了环形链表
//这时候get(23)就会一直查找下去,因为元素一直拥有next。从而导致 infinite loop
//resize后大小为8
map.put(3, "littlehow");
map.put(11, "color wolf");
map.put(7, "black dog");
map.put(15, "blue blood");
}

@Test
public void conflict() {
/**
* 想要出现Entry,V> next = e.next;之后挂起线程非常困难,在并发量超级大的情况下有可能会出现
* 所以没有出现死循环是最可能的现象,生产环境往往是不可预测的
* 在多线程环境下使用map这样结构的类有两点建议:
* 1.使用ConcurrentHashMap
* 2.如果确定map元素多少的情况,最好初始化map尽量大,避免rehash
*/
for (int i = 0; i <count; i ++) {
new Thread("thread-" + (i + 1)) {
@Override
public void run() {
map.put(19, "new person");
countDownLatch.countDown();
}
}.start();
}
try {
TimeUnit.SECONDS.sleep(1);
countDownLatch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
}

@After
public void over() {
System.out.println("value=" + map.get(23) + " , size=" + map.size());
}
}


推荐阅读
  • 单线程化的ConcurrentHashMap的性能要比同步的HashMap的性能稍好一些,而且在并发应用中,这种作用就十分明显了。ConcurrentHashMap的实现,假定大多数常用的操 ... [详细]
  • HashMap:键值对(key-value):通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value.默认是1:1关系:存在则覆盖,当key已经存在,则利用新的va ... [详细]
  • HashTable与ConcurrentHashMap均可实现HashMap的功能,对外提供了键值对存储的数据结构。但是在内部结构及实现上有何区别,性能上的差异到底在哪里又是如何导致的 ... [详细]
  • Java之HashMap在多线程情况下导致死循环的问题
    PS:不得不说Java编程思想这本书是真心强大..学习内容:1.HashMap<K,V>在多线程的情况下出现的死循环现象当初学Java的时候只是知道HashMap< ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 面向对象之3:封装的总结及实现方法
    本文总结了面向对象中封装的概念和好处,以及在Java中如何实现封装。封装是将过程和数据用一个外壳隐藏起来,只能通过提供的接口进行访问。适当的封装可以提高程序的理解性和维护性,增强程序的安全性。在Java中,封装可以通过将属性私有化并使用权限修饰符来实现,同时可以通过方法来访问属性并加入限制条件。 ... [详细]
  • 本文介绍了RxJava在Android开发中的广泛应用以及其在事件总线(Event Bus)实现中的使用方法。RxJava是一种基于观察者模式的异步java库,可以提高开发效率、降低维护成本。通过RxJava,开发者可以实现事件的异步处理和链式操作。对于已经具备RxJava基础的开发者来说,本文将详细介绍如何利用RxJava实现事件总线,并提供了使用建议。 ... [详细]
  • 使用freemaker生成Java代码的步骤及示例代码
    本文介绍了使用freemaker这个jar包生成Java代码的步骤,通过提前编辑好的模板,可以避免写重复代码。首先需要在springboot的pom.xml文件中加入freemaker的依赖包。然后编写模板,定义要生成的Java类的属性和方法。最后编写生成代码的类,通过加载模板文件和数据模型,生成Java代码文件。本文提供了示例代码,并展示了文件目录结构。 ... [详细]
  • ejava,刘聪dejava
    本文目录一览:1、什么是Java?2、java ... [详细]
  • Annotation的大材小用
    为什么80%的码农都做不了架构师?最近在开发一些通用的excel数据导入的功能,由于涉及到导入的模块很多,所以开发了一个比较通用的e ... [详细]
  • android布局基础及范例(二):人人android九宫格布局
    人人android是人人网推出的一款优秀的手机应用软件,我们在使用的时候发现他的首页布局是九宫格模式的,让人觉得很别致,因为现在很多的android软件很少使用这种布局模式,人人andr ... [详细]
  • 我有3个来自RESEARCHS的映射值,指定要使用参考数据集填充的行中的范围。该研究 ... [详细]
  • 有2种办法让HashMap线程安全,分别如下:  方法一:通过Collections.synchronizedMap()返回一个新的Map,这个新的map就是线程安全的。这个要求大家习惯基于接口编程 ... [详细]
  • 缓存这个东西就是为了提高运行速度的,由于缓存是在寸土寸金的内存里面,不是在硬盘里面,所以容量是很有限的。LRU这个算法就是把最近一次使用时间离现在时间最远的数据删除掉。先说说List:每 ... [详细]
author-avatar
奥奥奥尼瀚
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有