解决方案 1
package com.brian.interview.study.thread;
/**
* Copyright (c) 2020 ZJU All Rights Reserved
* <p>
* Project: JavaSomeDemo
* Package: com.brian.interview.study.thread
* Version: 1.0
* <p>
* Created by Brian on 2020/2/11 18:13
*/
import java.util.*;
/**
* 集合类不安全的问题
* ArrayList
*/
public class ContainerNotSafeDemo {
public static void main(String[] args) {
// List<String> list = new Vector<>();
List<String> list = Collections.synchronizedList(new ArrayList<>());
for (int i = 1; i <= 30; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(list);
}, String.valueOf(i)).start();
}
// java.util.ConcurrentModificationException
/**
* 1、故障现象
* java.util.ConcurrentModificationException
*
* 2、导致原因
*
* 3、解决方案
* 3.1、new Vector<>();
* 3.2、Collections.synchronizedList(new ArrayList<>());
* 3.3、???
*
* 4、优化建议(同样的错误不犯第2次)
*
*/
}
}
限制不可以用 Vector 和 Collections 工具类解决方案 2
CopyOnWriteArrayList
package com.brian.interview.study.thread;
/**
* Copyright (c) 2020 ZJU All Rights Reserved
* <p>
* Project: JavaSomeDemo
* Package: com.brian.interview.study.thread
* Version: 1.0
* <p>
* Created by Brian on 2020/2/11 18:13
*/
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
/**
* 集合类不安全的问题
* ArrayList
*/
public class ContainerNotSafeDemo {
public static void main(String[] args) {
}
private static void mapNoSafe() {
//Map<String, String> map = new HashMap<>();
//Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
Map<String, String> map = new ConcurrentHashMap<>();
for (int i = 1; i <= 30; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 8));
System.out.println(map);
}, String.valueOf(i)).start();
}
}
private static void setNoSafe() {
//Set<String> set = new HashSet<>();
//Set<String> set = Collections.synchronizedSet(new HashSet<>());
Set<String> set = new CopyOnWriteArraySet<>();
for (int i = 1; i <= 30; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(set);
}, String.valueOf(i)).start();
}
new HashSet<>().add("a");
/**
* HashSet底层是HashMap:
* Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
* default initial capacity (16) and load factor (0.75).
*
* add方法也是调用map的put方法 键为HashSet的值, 值为一个Object常量
*/
}
public static void listNotSafe() {
//List<String> list = new Vector<>();
//List<String> list = Collections.synchronizedList(new ArrayList<>());
List<String> list = new CopyOnWriteArrayList<>();
for (int i = 1; i <= 30; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(list);
}, String.valueOf(i)).start();
}
// java.util.ConcurrentModificationException
/**
* 1、故障现象
* java.util.ConcurrentModificationException
*
* 2、导致原因
* 并发争抢修改导致, 参考我们的花名册签名情况。
* 一个人正在写入, 另外一个同学过来抢夺, 导致数据不一致异常。并发修改异常。
*
* 3、解决方案
* 3.1、new Vector<>();
* 3.2、Collections.synchronizedList(new ArrayList<>());
* 3.3、new CopyOnWriteArrayList<>();
*
* 4、优化建议(同样的错误不犯第2次)
* 写时复制
* CopyOnWrite 容器即写时复制的容器。往一个容器添加元素的时候, 不直接往当前容器 Object[] 添加, 而是先将当前容器 Object[] 进行 Copy,
* 复制出一个新的容器 Object[] newElements, 然后新的容器 Object[] newElements 里添加元素, 添加完元素之后,
* 再将原容器的引用指向新的容器 setArray(newElements); 这样做的好处是可以对 CopyOnWrite 容器进行并发的读,
* 而不需要加锁, 因为当前容器不会添加任何元素。所以 CopyOnWrite 容器也是一种读写分离的思想, 读和写不同的容器
* public boolean add(E e) {
* final ReentrantLock lock = this.lock;
* lock.lock();
* try {
* Object[] elements = getArray();
* int len = elements.length;
* Object[] newElements = Arrays.copyOf(elements, len + 1);
* newElements[len] = e;
* setArray(newElements);
* return true;
* } finally {
* lock.unlock();
* }
* }
*/
}
}