public class ListTest {
public static void main(String[] args) {
List<Object> arrayList = new ArrayList<>();
for(int i=1;i<=10;i++){
new Thread(()->{
arrayList.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(arrayList);
},String.valueOf(i)).start();
}
}
}
会造成:
ArrayList 在并发情况下是不安全的!
解决方案:
1、切换成Vector就是线程安全的啦!
2、使用Collections.synchronizedList(new ArrayList<>());
3、使用JUC中的包:List arrayList = new CopyOnWriteArrayList<>();
public class ListTest {
public static void main(String[] args) {
List<Object> arrayList = new CopyOnWriteArrayList<>();
for(int i=1;i<=10;i++){
new Thread(()->{
arrayList.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(arrayList);
},String.valueOf(i)).start();
}
}
}
CopyOnWriteArrayList:写入时复制! COW 计算机程序设计领域的一种优化策略
多个线程调用的时候,list,读取的时候,固定的,写入(存在覆盖操作);在写入的时候避免覆盖,造成数据错乱的问题;
CopyOnWriteArrayList比Vector厉害在哪里?
Vector底层是使用synchronized关键字来实现的:效率特别低下。
CopyOnWriteArrayList使用的是Lock锁,效率会更加高效!
Set不安全
和List、Set同级的还有一个BlockingQueue 阻塞队列;
Set和List同理可得: 多线程情况下,普通的Set集合是线程不安全的;
解决方案还是两种:
- 使用Collections工具类的synchronized包装的Set类
- 使用CopyOnWriteArraySet 写入复制的JUC解决方案
//同理:java.util.ConcurrentModificationException
// 解决方案:
public class SetTest {
public static void main(String[] args) {
// Set<String> hashSet = Collections.synchronizedSet(new HashSet<>()); //解决方案1
Set<String> hashSet = new CopyOnWriteArraySet<>();//解决方案2
for (int i = 1; i < 100; i++) {
new Thread(()->{
hashSet.add(UUID.randomUUID().toString().substring(0,5));
System.out.println(hashSet);
},String.valueOf(i)).start();
}
}
}
HashSet底层是什么?
hashSet底层就是一个HashMap;
public HashSet() {
map = new HashMap<>();
}
//add 本质其实就是一个map的key,map的key是无法重复的,所以使用的就是map存储
//hashSet就是使用了hashmap key不能重复的原理
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
//PRESENT是什么? 是一个常量 不会改变的常量 无用的占位
private static final Object PRESENT = new Object();
Map不安全
回顾map的基本操作:
//map 是这样用的吗? 不是,工作中不使用这个
//默认等价什么? new HashMap<>(16,0.75);
Map<String, String> map = new HashMap<>();
//加载因子、初始化容量
默认加载因子是0.75,默认的初始容量是16
同样的HashMap基础类也存在并发修改异常!
public static void main(String[] args) {
//map 是这样用的吗? 不是,工作中不使用这个
//默认等价什么? new HashMap<>(16,0.75);
Map<String, String> map = new HashMap<>();
//加载因子、初始化容量
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();
}
}
结果同样的出现了:异常java.util.ConcurrentModificationException 并发修改异常
解决方案:
- 使用Collections.synchronizedMap(new HashMap<>());处理;
- 使用ConcurrentHashMap进行并发处理
- TODO:研究ConcurrentHashMap底层原理:
这里我们可以直接去研究一下,这个也是相当重要的。