java中arraylist线程不安全,可靠同步方式有四种:①collections.synchronizedlist包装,单操作安全但复合操作需手动同步;②copyonwritearraylist,读无锁、写复制,适合读多写少;③手动synchronized块,适用于逻辑组合操作;④不推荐vector,因性能差、api过时。

Java 中的 ArrayList 本身不是线程安全的,多线程环境下直接使用可能引发 ConcurrentModificationException 或数据不一致问题。要实现同步、保证线程安全,主要有以下几种可靠方式:
使用 Collections.synchronizedList 包装
这是最常用、最轻量的方式。它返回一个线程安全的 List 代理对象,底层通过在关键方法(如 add、get、size)上加 synchronized 锁来实现同步。
注意:虽然单个操作是线程安全的,但**复合操作仍需手动同步**。例如遍历必须显式加锁,否则可能抛出并发修改异常。
- 创建方式:
List<string> list = Collections.synchronizedList(new ArrayList());</string> - 安全遍历写法:
synchronized (list) { for (String s : list) { ... } }
使用 CopyOnWriteArrayList(适合读多写少场景)
这是 java.util.concurrent 包提供的线程安全 List 实现。它的核心机制是:每次写操作(如 add、remove)都会复制整个底层数组,读操作则无锁且始终访问快照。
优点是读操作完全无竞争、不会阻塞;缺点是写操作开销大、内存占用高、迭代器不反映实时变更。
- 适用场景:监听器列表、配置项缓存、状态订阅等读远多于写的场合
- 创建方式:
List<string> list = new CopyOnWriteArrayList();</string> - 无需额外同步,遍历天然安全
手动加 synchronized 块(细粒度控制)
如果已有共享的 ArrayList 实例,且需要对一组逻辑操作整体加锁(比如“检查是否存在再添加”),可自行用 synchronized 块包裹。
关键点是锁对象要统一,推荐用该 list 实例本身或一个专用的 final 锁对象,避免锁错对象导致失效。
- 示例:
private final List<string> list = new ArrayList(); private final Object lock = new Object(); public void addIfAbsent(String s) { synchronized (lock) { if (!list.contains(s)) { list.add(s); } } }</string> - 不建议直接
synchronized(list)(若 list 可能被外部替换,锁对象会变)
避免误区:Vector 并不推荐
Vector 虽然方法默认 synchronized,但它是早期类,性能差、API 过时(如 addElement)、扩展性弱。JDK 文档明确建议优先使用 ArrayList + 同步包装或并发集合。
另外,synchronizedList 返回的代理和 Vector 的同步粒度不同(前者方法级,后者部分方法锁整个对象),但两者都存在迭代需额外同步的问题,实际开发中已基本被更优方案替代。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











