arraylist本身非线程安全,多线程下需依场景选方案:collections.synchronizedlist仅单方法原子,复合操作须手动同步;copyonwritearraylist适合读多写少;还可选用concurrentlinkedqueue、concurrenthashmap或本地集合+合并等替代方式。

Java 中的 ArrayList 本身不是线程安全的,多线程环境下直接使用可能引发 ConcurrentModificationException 或数据不一致问题。要实现线程安全,不能只靠简单包装,需根据实际场景选择合适方案。
用 Collections.synchronizedList 包装(基础但需注意)
这是最直接的“包装”方式,返回一个同步代理列表:
List<string> syncList = Collections.synchronizedList(new ArrayList());</string>
⚠️ 注意:它只保证单个方法(如 add()、get())是原子的,**复合操作仍需手动同步**。例如遍历必须显式加锁:
synchronized (syncList) {
for (String s : syncList) { ... }
}
常见误区是以为包装后就能随意迭代,结果仍可能抛出异常或读到脏数据。
用 CopyOnWriteArrayList(适合读多写少)
这是专为并发设计的替代类,写操作时复制整个数组,读操作无锁、高性能:
- ✅ 读操作完全无锁,适合高并发读场景(如监听器列表、配置快照)
- ❌ 写操作开销大(复制 + GC 压力),不适合频繁增删
- ❌ 迭代器是快照,无法反映后续修改,也不支持
remove()等结构变更
示例:
List<string> list = new CopyOnWriteArrayList();
list.add("a"); // 内部复制数组
for (String s : list) { /* 安全,不会抛 ConcurrentModificationException */ }</string>
按需选用更合适的并发集合
很多时候,ArrayList 的使用意图其实是“动态数组+随机访问”,但并发下未必需要保留所有特性。可考虑以下替代:
-
需要有序且支持高频写入? → 用
ConcurrentLinkedQueue(非阻塞队列)或LinkedBlockingQueue(带界/阻塞),牺牲随机访问换线程安全 -
需要键值映射+并发? → 直接用
ConcurrentHashMap,比“同步 HashMap”高效得多 -
只是临时收集结果供后续处理? → 各线程用本地
ArrayList,最后用CollectionUtils.union()或流合并,避免共享状态
自己加锁控制(灵活但易错)
若业务逻辑复杂(如“检查存在再添加”),建议用显式锁封装操作逻辑,而非依赖集合自身同步:
private final List<string> list = new ArrayList();
private final ReentrantLock lock = new ReentrantLock();
<p>public void addIfAbsent(String item) {
lock.lock();
try {
if (!list.contains(item)) {
list.add(item);
}
} finally {
lock.unlock();
}
}</p></string>
这种方式可控性强,但需确保所有共享访问路径都走同一把锁,且注意避免死锁和锁粒度问题。
不复杂但容易忽略的是:线程安全的本质不是“让某个集合变安全”,而是“协调对共享状态的访问”。选对工具前,先理清读写比例、是否需要实时一致性、是否允许弱一致性等关键需求。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











