如何在多线程环境下避免快速失败异常?
在多线程环境下,可通过以下几种方式避免快速失败(Fail-Fast)异常:
1. 使用线程安全的集合类
Java 提供了多种线程安全的集合类,它们在迭代时不会抛出 ConcurrentModificationException
。
示例:使用 CopyOnWriteArrayList
java
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;public class CopyOnWriteExample {public static void main(String[] args) {List<String> list = new CopyOnWriteArrayList<>();list.add("apple");list.add("banana");// 线程 1:遍历集合Thread t1 = new Thread(() -> {Iterator<String> it = list.iterator();while (it.hasNext()) {System.out.println(it.next());try {Thread.sleep(100);} catch (InterruptedException e) {e.printStackTrace();}}});// 线程 2:修改集合Thread t2 = new Thread(() -> {try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}list.add("cherry"); // 不会触发异常});t1.start();t2.start();}
}
常用线程安全集合
CopyOnWriteArrayList
:适用于读多写少的场景,每次修改时会创建新数组。ConcurrentHashMap
:高效的线程安全 Map,支持并发读写。ConcurrentLinkedQueue
:无界线程安全队列,基于链表实现。
2. 使用同步机制
通过显式的同步(如 synchronized
块或 ReentrantLock
)来保证同一时间只有一个线程访问集合。
示例:使用 synchronized
块
java
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;public class SynchronizedListExample {private static final List<String> list = new ArrayList<>();private static final Object lock = new Object();public static void main(String[] args) {list.add("apple");list.add("banana");// 线程 1:遍历集合Thread t1 = new Thread(() -> {synchronized (lock) {Iterator<String> it = list.iterator();while (it.hasNext()) {System.out.println(it.next());}}});// 线程 2:修改集合Thread t2 = new Thread(() -> {synchronized (lock) {list.add("cherry");}});t1.start();t2.start();}
}
注意事项
- 同步会导致性能下降,尤其在读操作频繁时。
- 需要确保所有对集合的访问都使用相同的锁。
3. 使用 Collections.synchronizedList()
包装集合
将普通集合转换为同步集合,但迭代时仍需手动同步。
示例:
java
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;public class SynchronizedWrapperExample {public static void main(String[] args) {List<String> list = Collections.synchronizedList(new ArrayList<>());list.add("apple");list.add("banana");// 迭代时必须手动同步synchronized (list) {Iterator<String> it = list.iterator();while (it.hasNext()) {System.out.println(it.next());}}// 修改操作会自动同步list.add("cherry");}
}
4. 使用并发友好的迭代方式
某些并发集合提供了弱一致性(Weakly Consistent)的迭代器,允许在迭代过程中修改集合。
示例:ConcurrentHashMap
的弱一致性迭代器
java
import java.util.Iterator;
import java.util.concurrent.ConcurrentHashMap;public class ConcurrentHashMapExample {public static void main(String[] args) {ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();map.put("apple", 1);map.put("banana", 2);// 弱一致性迭代器允许并发修改Iterator<String> it = map.keySet().iterator();while (it.hasNext()) {String key = it.next();System.out.println(key);map.put("cherry", 3); // 不会抛出异常}}
}
根据具体业务场景选择合适的方案,优先考虑使用 Java 提供的并发集合类,避免手动同步带来的复杂性。