返回

如何远离ConcurrentModificationException的纠缠

后端

ConcurrentModificationException是一个在Java集合框架中常见的运行时异常。顾名思义,它表示在遍历集合时对集合进行了修改。

起因:
在jdk1.8之前,java集合是没有快速失败机制的。这意味着你可以一边遍历集合,一边对集合进行修改,而不会抛出任何异常。然而,这种机制也存在一个问题:如果两个线程同时对集合进行修改,那么就有可能导致数据不一致。

为了解决这个问题,jdk1.8专家们为集合增加了一种快速失败机制。当一个线程开始遍历集合时,它会创建一个副本。如果在遍历过程中,另一个线程对集合进行了修改,那么这个副本就会失效。当遍历线程试图使用这个副本时,就会抛出ConcurrentModificationException异常。

疑问:为什么简单的一个foreach循环时不时会报ConcurrentModificationException (补充:该异常的原因是jdk1.8之后专家们对集合增加的一种快速失败机制,在遍历时对集合进行修改会导致抛出这个异常)

解答:这只是导致ConcurrentModificationException异常产生的一个原因。事实上,任何对集合进行修改的操作都可能导致这个异常,即使你没有使用foreach循环。例如,如果你使用迭代器遍历集合,并在遍历过程中调用remove()方法来删除某个元素,那么也会抛出ConcurrentModificationException异常。

避免:
那么,如何避免ConcurrentModificationException异常呢?

  1. 使用并发安全的集合:
    Java集合框架中提供了多种并发安全的集合,这些集合可以在多线程环境下安全地使用。例如,你可以使用ConcurrentHashMap来代替HashMap,使用CopyOnWriteArrayList来代替ArrayList。

  2. 在遍历集合时,不要修改集合:
    这是避免ConcurrentModificationException异常的最简单的方法。如果你需要在遍历集合时修改集合,那么可以使用迭代器来遍历集合,并在遍历过程中使用remove()方法来删除某个元素。

  3. 使用synchronized来保护集合:
    如果你无法使用并发安全的集合,或者你必须在遍历集合时修改集合,那么你可以使用synchronized关键字来保护集合。例如,你可以使用以下代码来保护一个HashMap:

synchronized (map) {
  // 遍历map
}

这样,就可以避免在遍历map时对map进行修改,从而避免ConcurrentModificationException异常。