1、典型回答
ArrayList 是非线程安全的数据结构
多线程环境下,如果多个线程同时对同一个 ArrayList 进行添加、删除或修改操作,可能会导致数据不一致或发生异常。这是因为,ArrayList 在内部实现时,并没有添加任何线程同步的机制,所以如果有多个线程同时对ArrayList 进行修改时,就会导致线程不安全的问题发生。
2、全面剖析
ArrayList 是非线程安全的容器,它是设计在单线程底下使用的,所以如果同时有多个线程对 ArrayList 进行非查询操作时,就会造成线程安全问题
例如,添加操作和修改操作同时执行,那么它们的执行情况可能是这样的:
- 首先,先执行添加操作,而添加时发现 ArrayList 需要进行扩容,所以此时就先执行了扩容操作
- 扩容操作执行一半之后,当前线程 CPU 时间片用完了,停止执行
- 修改线程开始执行,于是将 ArrayList 已经扩容的这部分旧数据进行修改,修改线程执行完成
- 扩容操作继续执行,将后半一半数组进行扩容。
- 将原对象的引用更换到新数组上
此时就会发现,修改线程的修改操作失效了,因为修改线程,修改的是老数组,而添加操作在扩容时,已经将旧数据复制到新数组了,所以此时的修改操作就丢失了,这就是线程安全问题。
3、知识扩展
如何让 ArrayList 变成线程安全的?
想要让 ArrayList 变成线程安全的,也就是想要在多线程下使用 ArrayList 的方案有以下两类:
- 加锁:在多线程下,对 ArrayList 进行非查询操作时,先加锁,可以使用 synchronized 或 Lock,让线程排队执行,这样对于 ArrayList 的操作就变成单线程了,这样 ArrayList 就是线程安全的了。
- 更换同类型线程安全的容器:在多线程下可以将 ArrayList 更换为线程安全的 CopyOnWriteArrayList,这样也不会有线程安全问题
CopyOnWriteArrayList 是如何保证线程安全的? 请参考:
- CopyOnWriteArrayList是线程安全的吗?-CSDN博客
- 什么是 “写时复制”技术?-CSDN博客