前言
Java中的Map集合,常用的类型为HashMap<K,V>实现key-value类型数据的存储。key不可重复!
详细可以参考 hashmap源码分析(jdk1.8)
在单线程操作下,该集合可用性高,但在多线程下,该集合依旧存在不安全的问题。
Java多线程下Map不安全问题
如标题所示,在多线程下,多个线程操作同一个HashMap集合,进行增加元素操作时,会出现并发异常,代码案例如下所示:
import java.util.*;
public class MapTest {
public static void main(String[] args) {
Map<String,Object> maps = new HashMap<>();
for (int i = 1; i <= 40; i++) {
new Thread(()->{
maps.put(UUID.randomUUID().toString().substring(0,5),"6666");
System.out.println(Thread.currentThread().getName()+"=="+maps);
},String.valueOf(i)).start();
}
}
}
代码运行日志如下所示:
出现了 java.util.ConcurrentModificationException
!
Collections工具类下的安全集合
import java.util.*;
public class MapTest {
public static void main(String[] args) {
Map<String,Object> maps = Collections.synchronizedMap(new HashMap<>());
for (int i = 1; i <= 40; i++) {
new Thread(()->{
maps.put(UUID.randomUUID().toString().substring(0,5),"6666");
System.out.println(Thread.currentThread().getName()+"=="+maps);
},String.valueOf(i)).start();
}
}
}
运行日志如下所示:
并未出现java.util.ConcurrentModificationException
,其中该集合的源码结构如下所示:
由源码可以看出,Collections.synchronizedMap(Map<K,V> m)
生成的集合,会采取将new HashMap<>()
转化为java.util.Collections.SynchronizedMap
安全类几个,其中增加元素操作源码如下所示:
采取synchronized同步代码块
的方式实现。保证多个线程操作情况下的数据安全问题。
JUC下的安全Map集合
看下列案例所示:
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
public class MapTest {
public static void main(String[] args) {
Map<String,Object> maps = new ConcurrentHashMap<>();
for (int i = 1; i <= 40; i++) {
new Thread(()->{
maps.put(UUID.randomUUID().toString().substring(0,5),"6666");
System.out.println(Thread.currentThread().getName()+"=="+maps);
},String.valueOf(i)).start();
}
}
}
运行结果如下所示:
并未出现异常保存信息,观察其中增加元素源码逻辑如下:
发现数据的插入操作,采取的synchronized
关键字,修饰代码块的方式保证多线程下数据增加的安全性。