答案是肯定的,线程不安全。
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。

看底层代码可以看出,在调用add方法的时候并没有加锁,所以线程不安全。
List<String> list = new Vector<>(); //Vector是通过加入锁来实现线程安全的

List<String> list = Collections.synchronizedList(new ArrayList<>());
List<String> list =new CopyOnWriteArrayList<>();

写时复制
CopyOnWriteArrayList是一个写时复制的容器,在往容器中添加元素的时候,不是直接往当前容器elements添加,而是将当前容器进行拷贝,复制出来一个新的容器newElements,数据添加完成后,将原容器的引用指向新的容器setArray(newElements)。
这样做的好处是可以进行并发读,而不用加锁,因为当前容器不会添加任何元素,所以CopyOnWrite是一种读写分离的思想,读和写不是同一个容器。
CopyOnWriteArraySet<String> list =new CopyOnWriteArraySet<String>();
Map<String,String> list =new ConcurrentHashMap<>();