关于hashmap在多线程环境下的一个小实验
我们都知道hashmap是非线程安全的,平时我们经常是在单线程环境下使用这个类的,现在我们模拟一个多线程环境,并发操作访问一个hashmap实例,看看会出现什么匪夷所思的问题。
运行如下程序:
import java.util.HashMap;
public class TestMap {
private HashMap map = new HashMap(2, 0.5f);
public TestMap() {
Thread t1 = new Thread() {
public void run() {
for (int i = 0; i < 50000; i++) {
map.put(new Integer(i), i);
}
System.out.println("t1 over");
}
};
Thread t2 = new Thread() {
public void run() {
for (int i = 0; i < 50000; i++) {
map.put(new Integer(i), i);
}
System.out.println("t2 over");
}
};
Thread t3 = new Thread() {
public void run() {
for (int i = 50000; i < 100000; i++) {
map.put(new Integer(i), i);
}
System.out.println("t3 over");
}
};
Thread t4 = new Thread() {
public void run() {
for (int i = 100000; i < 150000; i++) {
map.put(new Integer(i), i);
}
System.out.println("t4 over");
}
};
Thread t5 = new Thread() {
public void run() {
for (int i = 150000; i < 200000; i++) {
map.put(new Integer(i), i);
}
System.out.println("t5 over");
}
};
Thread t6 = new Thread() {
public void run() {
for (int i = 0; i < 50000; i++) {
map.get(new Integer(i));
}
System.out.println("t6 over");
}
};
Thread t7 = new Thread() {
public void run() {
for (int i = 50000; i < 100000; i++) {
map.get(new Integer(i));
}
System.out.println("t7 over");
}
};
Thread t8 = new Thread() {
public void run() {
for (int i = 100000; i < 150000; i++) {
map.get(new Integer(i));
}
System.out.println("t8 over");
}
};
t1.start();
t2.start();
t3.start();
t4.start();
t5.start();
t6.start();
t7.start();
t8.start();
}
public static void main(String[] args) {
new TestMap();
}
}
刚开始我并未给构造器指定参数,为了提高问题复现的机率,我把map的初始容量和负载因子分别设为2和0.5,这样map的rehash操作就更加频繁了,多点击运行一下,就会发现有几个线程没有打印出结束标志,这是什么原因,难道线程可能进入了等待状态,或者死循环?
查看任务管理器,发现javaw线程cpu竟超过80%
利用jstack工具查看堆栈信息:
线程处于运行状态,程序进入了死循环,多个线程同时put,rehash的时候会导致循环链表的出现,用get方法获取就会出现inifinite loop。(疫苗:Java HashMap的死循环)这个问题现在看来一目了然,但在生产环境上,系统庞大,要找出问题根源是需要费一段时间的,当hashmap出现了让人匪夷所思的现象时,要想想它是否处于多线程环境。
另外,在运行这段代码时,有时也会报出如下异常:
Exception in thread "Thread-2" java.lang.ArrayIndexOutOfBoundsException: 26
at java.util.HashMap.getEntry(HashMap.java:463)
at java.util.HashMap.get(HashMap.java:417)
at map.TestMap$3.run(TestMap.java:36)
直接看源码可知,问题还是出在多个线程同时操作访问table变量上。
或许你在多线程环境下使用hashmap过程中碰到更多有趣的现象,请留言或投稿给我。
- Spring Boot开发Web应用
- C#/.NET RestSharp网络组件实现上传文件到远程服务器【可跨域传文件】
- android 自定义gallerey并实现预览功能
- Android学习第五弹之Matrix的用法
- 推荐一款超强大的基于Angularjs的自动完成(Autocomplete)标签及标签组插件–ngTagsInput
- Android新组件RecyclerView介绍,其效率更好
- android wheelview实现三级城市选择
- 算法之冒泡排序
- 数据结构之链表
- Spring Cloud实战小贴士:Zuul统一异常处理(三)【Dalston版】
- 算法之红黑树
- MIDlet工作原理
- 第五章 正则表达式的拆分【修订】
- 仿今天头条加载环境文字闪动效果
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 使用Python自动备份思科交换机配置
- c# winform 窗体最大化后挡住了任务栏
- Oracle参数解析(timed_statistics)
- C#将引用的dll嵌入到exe文件中
- C# 软件版本号
- C# 实现登录并跳转界面
- QT 常用控件操作实例集锦
- C# Socket TCP发送图片与接收图片
- ingress通过daemonSet,nodeSelector,hostNetwork方式部署
- Oracle参数解析(event)
- Qt读写文件(2种方式)实现详解
- 字符串匹配 - KMP算法
- c# 判断文件是否发生了变化
- C# 用IrisSkin4.dll美化你的WinForm
- Oracle参数解析(shared_pool_size)