List 类型的线程安全问题
CopyOnWriteArrayList(重点)
首先我们对 CopyOnWriteArrayList 进行学习,其特点如下:
它相当于线程安全的 ArrayList。和 ArrayList 一样,它是个可变数组;但是和ArrayList 不同的时,它具有以下特性:
- 它最适合于具有以下特征的应用程序:List 大小通常保持很小,只读操作远多于可变操作,需要在遍历期间防止线程间的冲突。
- 它是线程安全的。
- 因为通常需要复制整个基础数组,所以可变操作(add()、set() 和 remove()等等)的开销很大。
- 迭代器支持 hasNext(), next()等不可变操作,但不支持可变 remove()等操作。
- 使用迭代器进行遍历的速度很快,并且不会与其他线程发生冲突。在构造迭代器时,迭代器依赖于不变的数组快照。
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* 集合线程安全案例
*/
public class Test1 {
/**
* 多个线程同时对集合进行修改
* @param args
*/
public static void main(String[] args) {
List list = new CopyOnWriteArrayList();
for (int i = 0; i < 10; i++) {
new Thread(() ->{
list.add(UUID.randomUUID().toString().substring(0,5).toString());
System.out.println(list);
}, "线程" + i).start();
}
}
}
HashSet线程不安全
解决方案 CopyOnWriteArraySet
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* 集合线程安全案例
*/
public class Test1 {
/**
* 多个线程同时对集合进行修改
* @param args
*/
public static void main(String[] args) {
// List list = new CopyOnWriteArrayList();
Set<Object> set = new CopyOnWriteArraySet<>();
for (int i = 0; i < 10; i++) {
new Thread(() ->{
set.add(UUID.randomUUID().toString().substring(0,5).toString());
System.out.println(set);
}, "线程" + i).start();
}
}
}
HashMap线程不安全
解决方案 ConcurrentHashMap
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* 集合线程安全案例
*/
public class Test1 {
/**
* 多个线程同时对集合进行修改
* @param args
*/
public static void main(String[] args) {
// List list = new CopyOnWriteArrayList();
// Set<Object> set = new CopyOnWriteArraySet<>();
Map<Object, Object> map = new ConcurrentHashMap<>();
for (int i = 0; i < 10; i++) {
final int num = i;
new Thread(() ->{
map.put(num + "", UUID.randomUUID().toString().substring(0,5).toString());
System.out.println(map);
}, "线程" + i).start();
}
}
}