文章目录
提示:以下是本篇文章正文内容,下面案例可供参考
一、List
代码如下(示例):
java
public class ZZZZZZZZZZ {
public static void main(String[] args) {
// ArrList 非线程安全的集合
List<String> list1 = new ArrayList<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {// 多个线程同时向 ArrayList 添加元素
list1.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(list1);
}).start();
}
}
}
输出结果
Exception in thread "Thread-1" Exception in thread "Thread-0" Exception in thread "Thread-4" Exception in thread "Thread-25" Exception in thread "Thread-23" Exception in thread "Thread-17" Exception in thread "Thread-18" Exception in thread "Thread-27" java.util.ConcurrentModificationException
,并发修改异常,由于ArrayList 不是线程安全的容器,多个线程并发添加元素,会导致竞争现象,最终产生该异常。
故障出现
java.util.ConcurrentModificationException
导致原因
多线程并发争抢修改导致
解决方法
- 使用线程安全的容器,例如:Vector,在该类中每个方法都加上了 synchronized,不会导致线程安全问题,但是由于锁的粒度太细,会导致程序的速度较慢。
- 使用集合工具类的线程安全的方法,如:
java
static <T> List<T> Collections.synchronizedList(List<T> list)
- juc 下面的 CopyOnWriteArrayList,该类使用使用 ReentrantLock 加锁解锁,每次添加新元素就会加锁,然后开辟比旧数组多1的空间,将原数组全部拷贝进去,再将新元素加到最后一个位置。由于每次添加元素都会拷贝原数组,如果原数组很大,就会对内存资源造成很大的消耗,因此适合读多写少的场景。源码如下:
java
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();
}
}
二、Set
代码如下(示例):
java
public class ZZZZZZZZZZ {
public static void main(String[] args) {
// 非线程安全的 HashSet
Set<String> set = new HashSet<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {
set.add(UUID.randomUUID().toString().substring(0, 8));
System.out.println(set);
}).start();
}
}
}
故障出现
java.util.ConcurrentModificationException
导致原因
多线程并发争抢修改导致
解决方法
- 使用集合工具类的线程安全的方法,如:
java
static <T> Set<T> Collections.synchronizedList(Set<T> s)
- juc 下面的 CopyOnWriteArraySet,底层还是 CopyOnWriteArrayList,源码的构造方法如下:
java
public CopyOnWriteArraySet() {
al = new CopyOnWriteArrayList<E>();
}
三、Map
代码如下(示例):
java
public class ZZZZZZZZZZ {
public static void main(String[] args) {
// 非线程安全的 HashMap
Map<String, String> map = new HashMap<>();
for (int i = 0; i < 30; i++) {
new Thread(() -> {
map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 8));
System.out.println(map);
}).start();
}
}
}
故障出现
java.util.ConcurrentModificationException
导致原因
多线程并发争抢修改导致
解决方法
-
使用线程安全的容器,如:ConcurrentHashMap
-
使用集合工具类的线程安全的方法,如:
java
static <K, V> Map<K, V> Collections.synchronizedMap(Map<K, V> m)