正文
1. ArrayList是否线程安全
答案是肯定的,线程不安全。
public class TestArrayList {
public static void main(String[] args) {
List<String> list = new ArrayList<>();
for (int i = 0; i < 30; i++) {
new Thread(()->{
list.add(UUID.randomUUID().toString());
System.out.println(list);
}).start();
}
}
}
运行以上代码,抛出异常java.util.ConcurrentModificationException
。
2. 为什么线程不安全
看底层代码可以看出,在调用add方法的时候并没有加锁,所以线程不安全。
3. 如何解决线程不安全问题
3.1 Vector
List<String> list = new Vector<>(); //Vector是通过加入锁来实现线程安全的
3.2 Collections.synchronizedList
List<String> list = Collections.synchronizedList(new ArrayList<>());
3.3 CopyOnWriteArrayList(读写分离思想)
List<String> list =new CopyOnWriteArrayList<>();
写时复制
CopyOnWriteArrayList是一个写时复制的容器,在往容器中添加元素的时候,不是直接往当前容器elements
添加,而是将当前容器进行拷贝,复制出来一个新的容器newElements
,数据添加完成后,将原容器的引用指向新的容器setArray(newElements)
。
这样做的好处是可以进行并发读,而不用加锁,因为当前容器不会添加任何元素,所以CopyOnWrite
是一种读写分离的思想,读和写不是同一个容器。
4. set和map线程不安全解决
CopyOnWriteArraySet<String> list =new CopyOnWriteArraySet<String>();
Map<String,String> list =new ConcurrentHashMap<>();