Java 同步集合
Java 同步集合
同步集合的创建方式
通过 Collections 工具类提供的静态方法,可将普通集合转换为同步集合,保证多线程环境下单个方法操作的线程安全。
部分静态方法
synchronizedList(List<E> list):将普通 List(如 ArrayList)转换为同步 ListsynchronizedSet(Set<E> set):将普通 Set(如 HashSet)转换为同步 SetsynchronizedMap(Map<K,V> map):将普通 Map(如 HashMap)转换为同步 MapsynchronizedSortedSet(SortedSet<E> sortedSet):将普通 SortedSet(如 TreeSet)转换为同步 SortedSetsynchronizedSortedMap(SortedMap<K,V> sortedMap):将普通 SortedMap(如 TreeMap)转换为同步 SortedMap
代码示例
package com.collection;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author Jing61
*/
public class SynchronizedCollection {
private static List<String> list = new ArrayList<>();
public static void main(String[] args) {
/*
使用 Collections 提供的静态方法可以将集合换成同步的集合
1. synchronizedList(List<E> list)
2. synchronizedSet(Set<E> set)
3. synchronizedMap(Map<K,V> map)
4. synchronizedSortedSet(SortedSet<E> sortedSet)
5. synchronizedSortedMap(SortedMap<K,V> sortedMap)
*/
list = Collections.synchronizedList(list);
}
}
集合的“快速失败(Fail-Fast)”机制
快速失败的定义
“快速失败”是集合(以及多数普通集合)的一种错误检测机制,当多个线程并发操作集合,且至少有一个线程在修改集合结构(如添加、删除、清空元素) 时,迭代器会立即检测到这种并发修改行为,并抛出 java.util.ConcurrentModificationException 异常,终止迭代操作,避免出现更复杂的数据不一致或集合结构损坏问题。
快速失败的实现原理
集合的迭代器(如通过 iterator() 方法获取的迭代器)内部维护了一个 “修改计数器(modCount)”,核心逻辑如下:
- 迭代器创建时,会记录当前集合的
modCount值(记为expectedModCount)。 - 迭代过程中(如调用
next()方法),迭代器会对比currentModCount(集合当前的修改次数)与expectedModCount:- 若两者相等,说明迭代期间集合未被修改,继续迭代;
- 若两者不相等,说明迭代期间有其他线程修改了集合结构,立即抛出
ConcurrentModificationException。
- 当线程执行
add()、remove()等结构性修改操作时,集合的modCount会自动加 1。
快速失败的典型场景示例
场景1:迭代时其他线程修改集合结构
package com.collection;
import java.util.ConcurrentModificationException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* @author Jing61
*/
public class CollectionFailFast {
public static void main(String[] args) {
// 创建存储Integer的HashSet
Set<Integer> set = new HashSet<>();
for (int i = 0; i < 5; i++) {
set.add(i);
}
// 第一个线程:每秒添加元素
Thread addThread = new Thread(() -> {
int count = 5;
while (true) {
try {
Thread.sleep(1000);
set.add(count++);
System.out.println("\n添加元素: " + (count - 1));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
// 第二个线程:迭代器遍历
Thread iterateThread = new Thread(() -> {
while (true) {
try {
Thread.sleep(1000);
Iterator<Integer> iterator = set.iterator();
System.out.println("\n遍历:");
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
} catch (ConcurrentModificationException e) {
System.out.println("\n发生快速失败: " + e.getClass().getSimpleName());
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
addThread.start();
iterateThread.start();
}
}
避免快速失败的解决方案
快速失败的本质是“迭代器与集合修改操作的并发冲突”,可通过以下方式解决:
迭代期间锁住集合,禁止并发修改
利用同步集合本身的锁对象(或显式锁),确保迭代和修改操作互斥:
package com.collection;
import java.util.ConcurrentModificationException;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
/**
* @author Jing61
*/
public class CollectionFailFast {
public static void main(String[] args) {
// 创建存储Integer的HashSet
Set<Integer> set = new HashSet<>();
for (int i = 0; i < 5; i++) {
set.add(i);
}
// 第一个线程:每秒添加元素
Thread addThread = new Thread(() -> {
int count = 5;
while (true) {
synchronized (set) {
try {
Thread.sleep(1000);
set.add(count++);
System.out.println("\n添加元素: " + (count - 1));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
// 第二个线程:迭代器遍历
Thread iterateThread = new Thread(() -> {
while (true) {
synchronized (set) {
try {
Thread.sleep(1000);
Iterator<Integer> iterator = set.iterator();
System.out.println("\n遍历:");
while (iterator.hasNext()) {
System.out.print(iterator.next() + " ");
}
} catch (ConcurrentModificationException e) {
System.out.println("\n发生快速失败: " + e.getClass().getSimpleName());
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
addThread.start();
iterateThread.start();
}
}

浙公网安备 33010602011771号