上一篇我们说了ArrayList是个不安全的容器,这里我们再说说HashMap。
HashMap研究起来会比ArrayList更加有意思。
解决方案:
使用 ConcurrentHashMap 代替 HashMap
package com.zmkj.admin.test;
import java.util.HashMap;
import java.util.Map;
/**
* 线程不安全的容器 : HashMap
*
* @author sunminghao
*/
public class HashMapMultiThread {
static Map<String, String> map = new HashMap<>();
// static ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
public static class AddThread implements Runnable {
int start = 0;
public AddThread(int start){
this.start = start;
}
@Override
public void run() {
for (int i = start; i < 100000; i+=2) {
map.put(Integer.toString(i), Integer.toBinaryString(i));
}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new HashMapMultiThread.AddThread(0));
Thread t2 = new Thread(new HashMapMultiThread.AddThread(1));
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println(map.size());
}
/**
* 在执行过程中 其实可能会出现三种结果(注意:这里使用JDK 7进行实验)
*
* 一、程序正常结束,并且结果也是符合预期的,HashMap 的大小为 100000。
* 二、程序正常结束,但结果不符合预期,而是小于100000的数字,比如98868。
* 三、程序永远无法结束。
*
* 前两种就不多说了,其实和ArrayList情况类似。
* 第三种这里简单说一下,其实我们打开任务管理器的话就会发现,这段代码占用极高的CPU,最有可能的就是占用了两个CPU核,并使得
* 两个核的CPU 使用率达到了100%。这就类似死循环的情况。
* 接下来可以使用jstack工具进行查看程序的线程信息,再去分析。
*
* 简单了解就OK了 在JDK 8种已经不存在死循环的情况了,JDK 8 对HashMap 内部实现做了大规模的调整,因此规避了这个问题。
*
* 即使这样,贸然在多线程环境下使用HashMap 依然会导致内部数据不一致。
*
* TODO 解决方案:使用 ConcurrentHashMap 代替 HashMap
*
*/
}