返回
Java 循环陷阱:在 for-each 中删除集合数据导致异常原理
后端
2023-10-25 09:07:21
并发修改异常:理解和避免
并发修改异常(ConcurrentModificationException)是 Java 中的运行时异常,当我们在遍历集合(例如 ArrayList)时,如果在遍历过程中尝试修改集合(例如添加或删除元素),就会遇到此异常。
当多线程同时访问集合时,就会发生并发修改异常。如果一个线程正在遍历集合,而另一个线程同时修改集合,就会导致并发修改异常。
例如,以下代码演示了在遍历 ArrayList 时删除元素的常见场景:
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
for (String element : list) {
if (element.equals("B")) {
list.remove(element);
}
}
当我们运行这段代码时,将会遇到并发修改异常。这是因为我们在遍历集合时尝试修改集合。
避免并发修改异常的技巧
要避免并发修改异常,我们可以采取以下技巧:
- 使用迭代器(Iterator)
使用迭代器(Iterator)来遍历集合,可以避免并发修改异常。迭代器提供了一种安全的方式来遍历集合,它允许我们在遍历过程中修改集合而不抛出异常。
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) {
String element = iterator.next();
if (element.equals("B")) {
iterator.remove();
}
}
- 使用并发集合(Concurrent Collections)
Java 提供了一些并发集合,可以安全地用于多线程环境中。并发集合可以防止并发修改异常的发生。
例如,我们可以使用 ConcurrentHashMap 来代替 HashMap,使用 CopyOnWriteArrayList 来代替 ArrayList。
ConcurrentHashMap<String, Integer> map = new ConcurrentHashMap<>();
map.put("A", 1);
map.put("B", 2);
map.put("C", 3);
for (String key : map.keySet()) {
if (key.equals("B")) {
map.remove(key);
}
}
- **使用 synchronized **
我们可以使用 synchronized 关键字来同步对集合的访问。这样可以防止多个线程同时修改集合,从而避免并发修改异常。
List<String> list = new ArrayList<>();
list.add("A");
list.add("B");
list.add("C");
synchronized (list) {
for (String element : list) {
if (element.equals("B")) {
list.remove(element);
}
}
}
结论
并发修改异常是一个常见的错误,它会导致程序崩溃。为了避免并发修改异常,我们可以使用迭代器、并发集合或 synchronized 关键字来同步对集合的访问。