个性化阅读
专注于IT技术分析

Java中的ConcurrentModificationException

点击下载

当试图在不允许的情况下同时修改对象时, 会发生ConcurrentModificationException。当使用Java Collection类时, 通常会发生此异常。

例如-当某个其他线程在其上迭代时, 不允许线程修改Collection。这是因为迭代的结果变得不确定。 Iterator类的某些实现会引发此异常, 包括JRE提供的所有那些Iterator的通用实现。执行此操作的迭代器称为快速失败, 因为它们在遇到这种情况时会立即抛出异常, 而不是在将来的任何时候都面对集合的不确定行为。

注意:仅当某些其他线程试图修改Collection对象时才抛出此异常不是强制性的。如果单个线程调用了一些试图违反对象约定的方法, 则也会发生这种情况。当线程尝试通过某些快速故障迭代器迭代Collection对象时, 这种情况可能会发生, 迭代器将引发异常。

import java.awt.List;
import java.util.*;

public class Concurrentmodificationexception {

	public static void main(String[] args) {
		ArrayList<Integer> list = new ArrayList<>();

		list.add(1);
		list.add(2);
		list.add(3);
		list.add(4);
		list.add(5);

		Iterator<Integer> it = list.iterator();
		while (it.hasNext()) {                 
Integer value = it.next();            
			System.out.println("List Value:" + value);
			if (value.equals(3))
				list.remove(value);
		}

	}

}

输出:

Java中的ConcurrentModificationException

该消息表明, 当迭代器正在迭代列表并且我们正在同时对其进行修改时, 调用下一个方法时将引发异常。但是, 如果我们像下面给出的那样在哈希图中进行修改, 那么它将不会抛出任何此类异常, 因为哈希图的大小不会改变。

例如-

import java.awt.List;
import java.util.*;

public class concurrentmodificationexception {

	public static void main(String[] args) {
		
		HashMap<Integer, Integer> map = new HashMap<>();
		map.put(1, 1);
		map.put(2, 2);
		map.put(3, 3);
		
		Iterator<Integer> it = map.keySet().iterator();
		while(it.hasNext()) {
			Integer key = it.next();
			System.out.println("Map Value:" + map.get(key));
			if (key.equals(2)) {
				map.put(1, 4);
			}
		}	
	}
}

输出:

Map Value:1
Map Value:2
Map Value:3

此示例完全正常, 因为迭代器在地图上进行迭代时, 地图的大小没有改变。 if语句中仅更新映射。

ConcurrentModificationException的构造方法

ConcurrentModificationException有4种构造函数-

  1. public ConcurrentModificationException()-这将创建一个不带参数的ConcurrentModificationException。
  2. public ConcurrentModificationException(String message)这将创建一个ConcurrentModificationException, 并带有指定Exception的详细消息。
  3. public ConcurrentModificationException(Throwable cause)这将创建一个ConcurrentModificationException, 其原因和消息为(cause == null?null:cause.toString())。稍后通过Throwable.getCause()检索原因。
  4. public ConcurrentModificationException(String message, Throwable cause)这将创建带有详细消息和原因的ConcurrentModificationException。 (cause == null?null:cause.toString())。稍后, 该消息由Throwable.getMessage()检索, 而原因随后由Throwable.getCause()检索。

如何在多线程环境中避免ConcurrentModificationException?

为了避免在多线程环境中发生ConcurrentModificationException, 我们可以采用以下方法:

  1. 除了遍历集合类, 我们还可以遍历数组。这样, 我们可以很好地处理小型列表, 但是如果数组很大, 则会降低性能。
  2. 另一种方法可以通过将列表放入同步块来锁定它。这不是一种有效的方法, 因为它放弃了使用多线程的唯一目的。
  3. JDK 1.5或更高版本提供了ConcurrentHashMap和CopyOnWriteArrayList类。这些类有助于我们避免并发修改异常。

如何在单线程环境中避免ConcurrentModificationException?

通过使用迭代器的remove()函数, 你可以从基础集合对象中删除一个对象。


赞(0)
未经允许不得转载:srcmini » Java中的ConcurrentModificationException

评论 抢沙发

评论前必须登录!