当前位置: 首页 > 知识库问答 >
问题:

并发修改异常发生在预期的时间

翁和颂
2023-03-14

有一个列表正在被两个线程同时排序和迭代。不出所料,它导致ConcurrentModificationException。不清楚的是错误的时间。

import java.util.stream.*;
import java.util.*;

public class Confusionist {
    static List<Integer> numbers;
    public static void main(String args[]) {
      numbers = IntStream.generate(() -> java.util.concurrent.ThreadLocalRandom.current().nextInt()).limit(100).boxed().collect(Collectors.toList());
      new Thread(new Accessor()).start();
      new Thread(new Accessor()).start();
    }
    
    static class Accessor implements Runnable{
        public void run(){
            String threadName = Thread.currentThread().getName();
            char threadDenoter = threadName.charAt(threadName.length()-1);
            System.out.printf("Thread: %s, Going to sort\n", threadName);
            Collections.sort(numbers, Integer::compareTo);
            Iterator<Integer> iterator = numbers.iterator();
            System.out.printf("Thread: %s, Going to iterate\n", threadName);
            while(iterator.hasNext()){
                iterator.next();
                System.out.printf("%c", threadDenoter);
            }
        }
    }
}

输出:(出现几次)

Thread: Thread-0, Going to sort
Thread: Thread-1, Going to sort
Thread: Thread-0, Going to iterate
0000000000000000000000000000000000000000000000000000000000000000000000000000000Exception in thread "Thread-0" java.util.ConcurrentModificationException
    at java.base/java.util.ArrayList$Itr.checkForComodification(ArrayList.java:1013)
    at java.base/java.util.ArrayList$Itr.next(ArrayList.java:967)
    at HelloCodiva$Accessor.run(HelloCodiva.java:21)
    at java.base/java.lang.Thread.run(Thread.java:831)
000000Thread: Thread-1, Going to iterate
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
Completed with exit code: 0
  1. 为什么当第一个线程完成时,另一个线程的迭代失败?
  2. 当两个线程分别完成排序并获得迭代器时,底层迭代器将不会改变。为什么在此阶段会导致异常?

共有1个答案

诸葛砚
2023-03-14

当两个线程分别完成排序并获得迭代器时,底层迭代器不会改变。为什么这会导致这个阶段的异常?

这种假设是不正确的,因为列表已经排序,第二次排序不会使迭代器无效。如果thread-1在thread-0初始化了迭代器之后对列表进行排序,则thread-0获取的迭代器将变得无效,并在访问时引发ConcurrentModificationException。

我可以想出一个操作序列来解释消息/错误。假设thread-0对列表进行了排序,创建了一个迭代器并打印了80个奇数,然后发生了上下文切换。线程-1将调用数组并打印100次。现在,当thread-0重新调度时,它的迭代器将不再有效,并抛出异常。

List<Integer> list =
        IntStream.generate(() -> java.util.concurrent.ThreadLocalRandom.current().nextInt(10))
            .limit(10)
            .boxed()
            .collect(Collectors.toList());
    Collections.sort(list, Integer::compareTo);
    Iterator<Integer> itr = list.iterator();
    Collections.sort(list, Integer::compareTo);

    while (itr.hasNext()) {
      System.out.println(itr.next());
    }

有趣的是,这只适用于list collectors.tolist()返回类型。如果只是使用ArrayList我不会看到相同的行为。

 类似资料:
  • 问题内容: 我有这段代码,它给了我并发修改异常。即使看不到任何并发修改,我也无法理解为什么继续得到它。 问题答案: 为了避免,你应该这样编写代码: 允许你在迭代期间修改列表,但不能在创建和使用列表之间进行修改。

  • 当我使用temp=iterator.next()时,sort方法会导致并发修改错误。你能帮我解决并发修改错误吗。我给出了整个类的代码,但我只是尝试完成sort方法。事先谢谢你的帮助。 我必须对ArrayList中的所有数组进行排序。

  • 问题内容: 您能否告诉我在单线程环境中是否有可能发生并发修改异常的方法,我下面发布的以下应用程序由两个线程组成,请告诉我我也可以在单个线程中看到相同的异常..请劝告 是的,我知道,在单线程环境中,此错误可能会出现..如下面的代码所示。 请告知解决该问题的方法是什么..这样就不会出现此错误.. !! 问题答案: 可以在单线程环境中引发A。只要在不应该​​在上下文中修改对象的情况下使用它,就不必在另一

  • 当Maven构建我的项目并运行单元测试时,有时会抛出一个并发修改异常(大约5次中有1次会失败,其他时间会成功构建)。但是当我以单元测试的形式在本地运行测试时,它们都会毫无例外地通过。 在我的pom.xml文件我有Surefire插件配置为: 然而,我得到的stackTrace没有提到是什么导致了并发修改异常。 我注意到所有的测试都通过了构建,但是出于某种原因,Maven重新打印了已经通过但现在有测

  • 下面我需要帮助:我有两种方法: 第二种方法 在for循环中的方法calculatime中,我只得到第一个项目的结果,然后得到与标题相同的错误。请帮帮我,为这个案子多解释一下。

  • 问题内容: 我正在为我的大学课程使用一些代码,并从 至: 但是新方法不断给出并发修改错误。我如何解决这个问题,为什么会发生呢? 问题答案: 这是因为执行后您继续遍历该列表。 您正在同时读取和写入列表,这破坏了foreach循环下面的迭代器协定。 用 描述如下: 返回迭代中的下一个元素。 如果迭代没有更多元素,则抛出该异常。 您可以用来检查下一个元素是否可用。