一、多线程下集合类型安全方案
产生原因:
多线程并发场景下,操作如 ArrayList 这种不安全的集合会出现问题,可能后面写入的会覆盖前面的
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
/**
* 多线程并发场景下,操作 ArrayList 不安全
*/
public class DemoList {
public static void main(String[] args) {
//并发下 ArrayList 不安全
List<String> list = new ArrayList<>();
for (int i = 1; i <= 100; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(list);
}, String.valueOf(i)).start();
}
}
}
会出现异常 :ConcurrentModificationException
什么是CopyOnWrite
多线程调用的时候:
读取场景:直接对数据进行读取
写入场景:写入的情况将原先的复制一份,在复制的上面进行写入,写入完成,将此数据覆盖元原先的数据
目的:在写入时避免覆盖,造成数据问题
1、List 多线程解决方案
解决方案:
- List<String> list = new Vector<>();
- List<String> list = Collections.synchronizedList(new ArrayList<>());
- List<String> list = new CopyOnWriteArrayList<>();
推荐使用:CopyOnWriteArrayList
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 多线程并发场景下,操作 ArrayList 不安全
*/
public class DemoList {
public static void main(String[] args) {
//并发下 ArrayList 不安全
//List<String> list = new ArrayList<>();
/**
* 解决方案:
* 1、List<String> list = new Vector<>();
* 2、List<String> list = Collections.synchronizedList(new ArrayList<>());
* 3、List<String> list = new CopyOnWriteArrayList<>();
*/
List<String> list = new CopyOnWriteArrayList<>();
// CopyOnWrite:写入时复制 COW 计算机程序设计领域的一种优化策略
// 多线程调用的时候:
// 读取场景:直接对数据进行读取
// 写入场景:写入的情况将原先的复制一份,在复制的上面进行写入,写入完成,将此数据覆盖元原先的数据
// 目的:在写入时避免覆盖,造成数据问题
for (int i = 1; i <= 100; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(list);
}, String.valueOf(i)).start();
}
}
}
2、Set 多线程解决方案
解决方案:
- Set<String> set = Collections.synchronizedSet(new HashSet<>());
- CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
推荐使用:CopyOnWriteArraySet
import java.util.*;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* 多线程并发场景下,操作 HashSet 不安全
*/
public class DemoSet {
public static void main(String[] args) {
//并发下 HashSet 不安全
// Set<String> set = new HashSet<>();
/**
* 解决方案:
* 1、Set<String> set = Collections.synchronizedSet(new HashSet<>());
* 2、CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
*/
CopyOnWriteArraySet<String> set = new CopyOnWriteArraySet<>();
for (int i = 1; i <= 100; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString().substring(0, 5));
System.out.println(set);
}, String.valueOf(i)).start();
}
}
}
3、Map 多线程解决方案
解决方案:
- Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
- Map<String, String> map = new ConcurrentHashMap<>();
推荐使用:ConcurrentHashMap
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
/**
* 多线程并发场景下,操作 HashMap 不安全
*/
public class DemoMap {
public static void main(String[] args) {
//并发下 HashSet 不安全
// Map<String, String> map = new HashMap<>();
/**
* 解决方案:
* 1、Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
* 2、Map<String, String> map = new ConcurrentHashMap<>();
*/
Map<String, String> map = new ConcurrentHashMap<>();
for (int i = 1; i <= 100; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 5));
System.out.println(map);
}, String.valueOf(i)).start();
}
}
}