为什么这段代码不触发 ConcurrentModificationException?

Why this code does not trigger ConcurrentModificationException?

我正在从多个线程修改同一个列表,它不应该触发吗 迭代列表时出现 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();
    }
}

ConcurrentModificationException 当您在迭代列表时修改列表时触发。在你的代码中 qhen 你在列表上迭代时,你只休眠线程而不修改 it.This 会触发异常:

for(String s: list) {
    list.add("something");
}

你有没有检查下面的块是否抛出异常

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() 错误消息以检查其是否抛出错误。

您的代码确实(并且可以)生成 ConcurrentModificationException。你不是抓住它来打印它。

从下面可以看出确实抛出了很多ConcurrentModificationException.

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

注意: 来自 javadoc,

Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification. Fail-fast iterators throw {@code ConcurrentModificationException} on a best-effort basis. Therefore, it would be wrong to write a program that depended on this exception for its correctness: the fail-fast behavior of iterators should be used only to detect bugs

另见:java.util.ConcurrentModificationException not thrown when expected


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