Appearance
集合线程不安全演示
java
package io.alex.concurrent;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class UnsafeListDemo {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 0; i < 100; i++) {
new Thread(() -> {
list.add(UUID.randomUUID().toString().substring(0,8));
System.out.println(list);
}).start();
}
}
}
集合不安全的原因
- 缺乏同步, ArrayList 中的操作方法(如 add, remove, get 等)并没有内置的同步机制。因此,在并发环境下,多个线程同时修改 ArrayList 可能会导致数据不一致或其它问题。
- 结构修改时的并发问题:在结构修改(如增删元素)过程中,ArrayList 可能需要调整内部数组的大小或者元素的位置。如果这些操作在没有同步保护的情况下被并发执行,可能会导致数组越界或数据丢失。
- 解决方法:使用线程安全的集合类,如
Vector
、Collections.synchronizedList
、CopyOnWriteArrayList
等。
Vector 和 ArrayList 的区别
- Vector 是通过 synchronized 关键字来保证线程安全的,而 ArrayList 是非线程安全的。
Collections.synchronizedList
- Collections.synchronizedList 方法返回一个线程安全的 List,它通过对 List 的每个方法调用都加上了 synchronized 关键字来实现线程安全。
CopyOnWriteArrayList
- CopyOnWriteArrayList 是一个线程安全的 List,它通过在修改操作时,对原有数组进行复制来实现线程安全。因此,CopyOnWriteArrayList 适用于读多写少的场景。
- CopyOnWriteArrayList 的缺点是在写操作时,需要复制一个新的数组,因此写操作的性能较差。
- CopyOnWriteArrayList 的优点是读操作不需要加锁,因此读操作的性能较好。
- CopyOnWriteArrayList.add() 的源码:
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();
}
}