使用 collections.synchronizedlist 可以将一个普通的 arraylist 包装成线程安全的列表,其核心做法是调用该方法并传入目标列表,返回的对象会在每次单步操作时自动获取内部锁。需要注意的是,该包装类仅保证单个方法的原子性,迭代等复合操作必须手动在同步块中加锁,否则可能抛出 concurrentmodificationexception。

如何创建并使用同步列表进行基础读写
通过 Collections.synchronizedList(new ArrayList()) 即可创建实例,随后像普通列表一样调用 add、get 等方法,这些操作会自动获得对象监视器锁以保障线程安全。

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class SyncListDemo {
public static void main(String[] args) {
List<string> list = new ArrayList();
List<string> syncList = Collections.synchronizedList(list);
// 线程A:添加元素
Thread t1 = new Thread(() -> {
for (int i = 0; i {
for (int i = 0; i <p>运行上述代码后,控制台将按顺序打印 <code>Item-0</code> 到 <code>Item-4</code>。由于 <code>add</code> 和 <code>get</code> 都是单步方法,它们各自被同步块包裹,因此即使多线程并发访问也不会出现数据竞争或索引越界异常(前提是索引存在)。</p>
<h2>为什么迭代时必须手动加锁</h2>
<p>虽然 <code>synchronizedList</code> 的 <code>iterator()</code> 方法本身是同步的,但它返回的迭代器并不具备“快速失败”之外的额外保护,如果在迭代过程中其他线程修改了列表结构,就会触发 <code>ConcurrentModificationException</code>。因此,必须在外部显式地锁定列表对象。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill12835" title="JavaScript 测试模式"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20cf0281539.jpg" alt="JavaScript 测试模式" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill12835" title="JavaScript 测试模式" class="overflowclass">JavaScript 测试模式</a>
<p class="overflowclass">使用 Jest、Vitest 和 Testing Library 实施全面的测试策略,包括单元测试、集成测试和端到端测试,涵盖模拟、测试夹具和测试驱动开发。在编</p>
</div>
<a rel="nofollow" href="/xiazai/skill12835" title="JavaScript 测试模式" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
<p><img src="https://img.php.cn/upload/article/001/242/473/179463039526255.png?x-oss-process=image/resize,p_40" alt="Java ArrayList Collections.synchronizedList 怎么用"></p>
<pre class="brush:php;toolbar:false;">import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class SafeIterationDemo {
public static void main(String[] args) {
List<string> list = new ArrayList();
List<string> syncList = Collections.synchronizedList(list);
syncList.add("A");
syncList.add("B");
syncList.add("C");
// 正确的迭代方式:手动加锁
synchronized (syncList) {
Iterator<string> it = syncList.iterator();
while (it.hasNext()) {
String item = it.next();
System.out.println(item);
// 注意:不能在迭代期间直接调用 syncList.remove()
}
}
}
}</string></string></string>
执行这段代码会依次输出 A、B、C。关键在于 synchronized (syncList) 这一行,它确保了从获取迭代器到遍历结束的整个时间段内,没有其他线程能插入或删除元素。如果不加这个锁,当另一个线程正在执行 add 操作时,当前迭代器的状态可能会失效,导致程序崩溃。
在迭代过程中移除元素的具体问题
如果在同步块的迭代过程中尝试直接调用 syncList.remove(),会因为迭代器与底层集合的状态不一致而报错。正确的做法是使用迭代器自身的 remove() 方法,或者在同步块内重新获取迭代器。
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class RemoveDuringIterationDemo {
public static void main(String[] args) {
List<string> list = new ArrayList();
List<string> syncList = Collections.synchronizedList(list);
syncList.add("X");
syncList.add("Y");
syncList.add("Z");
synchronized (syncList) {
Iterator<string> it = syncList.iterator();
while (it.hasNext()) {
String item = it.next();
if (item.equals("Y")) {
it.remove(); // 安全移除
}
}
}
System.out.println(syncList); // 输出 [X, Z]
}
}</string></string></string>
运行结果将输出 [X, Z]。这里 it.remove() 是迭代器提供的安全删除机制,它会同时更新迭代器和底层集合的状态,避免了并发修改检查的触发。如果改用 syncList.remove(item),则需要在每次删除后重新获取迭代器,因为底层的 modCount 会改变,导致当前迭代器失效。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










