科技生活指南
柔彩主题三 · 更轻盈的阅读体验

线程安全的ArrayList怎么做(实战经验分享)

发布时间:2025-12-13 12:05:14 阅读:295 次

ref="/tag/413/" style="color:#643D3D;font-weight:bold;">线程安全的ArrayList怎么做

在日常开发中,尤其是处理多线程环境下的数据共享时,经常会用到集合类。ArrayList 是 Java 中最常用的动态数组,但它本身不是线程安全的。如果多个线程同时对一个 ArrayList 进行读写操作,很可能出现数据不一致、抛出异常,甚至程序崩溃。

比如你在做一个后台服务,接收用户提交的订单信息,多个线程同时往一个列表里添加订单记录。这时候如果直接用 ArrayList,轻则漏掉几条数据,重则程序直接报 ConcurrentModificationException。那怎么解决?

使用 Collections.synchronizedList

最简单的方式是用 Collections 提供的工具方法,把普通的 ArrayList 包装成线程安全的版本。

import java.util.*;

List<String> list = Collections.synchronizedList(new ArrayList<>());
list.add("订单1");
list.add("订单2");

这个方法返回的 list 在每个方法调用上都加了同步锁,保证了线程安全。但要注意:遍历时仍需手动加锁,否则可能出问题。

synchronized (list) {
    for (String item : list) {
        System.out.println(item);
    }
}

使用 CopyOnWriteArrayList

如果你的场景是读多写少,比如缓存配置、监听器列表,推荐用 CopyOnWriteArrayList。它是并发包中专为线程安全设计的列表实现。

它的原理是:每次修改(add、set、remove)都会创建一个新的副本,而读操作不需要加锁,因此读效率非常高。

import java.util.concurrent.CopyOnWriteArrayList;

CopyOnWriteArrayList<String> list = new CopyOnWriteArrayList<>();
list.add("用户上线");
list.add("用户上线");
for (String s : list) {
    System.out.println(s);
}

虽然写操作成本高,但在像消息广播、事件通知这类场景下,表现非常稳定。

自己加锁控制

如果你需要更精细的控制,也可以用 synchronized 关键字或 ReentrantLock 手动管理线程安全。

List<String> list = new ArrayList<>();
Object lock = new Object();

// 多线程中操作
synchronized (lock) {
    list.add("新增任务");
}

这种方式灵活,但容易出错,比如忘了加锁,或者锁的范围不对,反而带来隐患。

实际选择哪种方式,得看具体业务。如果是高频读、偶尔写的场景,CopyOnWriteArrayList 更合适;如果只是临时需要线程安全,synchronizedList 就够用了;而对性能和控制要求高的,可以自己加锁,但要小心处理。