为什么此代码不触发ConcurrentModificationException?

时间:2019-11-19 08:51:33

标签: java java.util.concurrent threadpoolexecutor

我正在从多个线程修改同一列表,是否应该触发 迭代列表时出现ConcurrentModificationException?

如何触发此异常?

public class ConcurrentTest {

    static List<String> list = setupList();

    public static List<String> setupList() {
        System.out.println("setup predefined list");

        List<String> l = new ArrayList();
        for(int i = 0; i < 50;i++) {
            l.add("test" + i);
        }

        return l;
    }

    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(50);

        for(int i = 0; i < 50; i++) {
            executorService.submit( () -> {     
                list.add("key1");       

                Thread currentThread = Thread.currentThread();
                System.out.println( Thread.currentThread().getName() + ", " + list.size() );

                for(String val: list) {
                    try {
                        Thread.sleep(25);
                    }
                    catch(Exception e) {

                    }
                }

            });
        }

        executorService.shutdown();
    }
}

3 个答案:

答案 0 :(得分:1)

在对列表进行迭代时修改列表时,会触发ConcurrentModificationException。在您遍历列表的代码中,您仅使线程处于睡眠状态,而不修改线程。这将触发异常:

path

答案 1 :(得分:1)

您是否检查了下面的块是否抛出异常。

try {
    list.add("key1");       

    Thread currentThread = Thread.currentThread();
    System.out.println( Thread.currentThread().getName() + ", " + list.size() );

    for(String val: list) {
        try {
            Thread.sleep(25);
        }
        catch(Exception e) {

        }
    }
}catch (Exception e) {
    e.printStackTrace();
}

请环绕try ... catch块和print()错误消息以检查其是否抛出错误。

答案 2 :(得分:0)

您的代码确实(并且可以)产生ConcurrentModificationException。您没有抓住它来打印它。

通过下面的内容,我们可以看到它确实抛出了许多ConcurrentModificationException

try {
    for (String val : list) {
        try {
          Thread.sleep(25);
        } catch (Exception e) {
        }
    }
} catch (Exception e) {
    e.printStackTrace();
}

注意:在Javadoc中,

  

请注意,不能保证迭代器的快速失败行为     因为通常来说,不可能在     存在不同步的并发修改。快速迭代器     尽最大努力抛出{@code ConcurrentModificationException}。     因此,编写依赖于此的程序是错误的     正确性的例外:迭代器的快速失败行为     应该仅用于检测错误

另请参阅:java.util.ConcurrentModificationException not thrown when expected


或者,您可以获取返回的Future并将它们收集在列表中。这样,在(至少)一种期货上调用get时,您将获得异常。