【问题标题】:Why this code does not trigger ConcurrentModificationException?为什么这段代码不会触发 ConcurrentModificationException?
【发布时间】:2019-11-19 08:51:33
【问题描述】:

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

【问题讨论】:

    标签: java java.util.concurrent threadpoolexecutor


    【解决方案1】:

    当您在迭代列表时修改列表时会触发 ConcurrentModificationException。在您的代码中,当您在列表上进行迭代时,您只会休眠线程而不修改它。这将触发异常:

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

    【讨论】:

    • 这不是真的。 same 列表正在从其他线程修改
    【解决方案2】:

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

    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() 错误消息来检查它的抛出错误与否。

    【讨论】:

      【解决方案3】:

      您的代码确实(并且可以)生成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 时遇到异常。

      【讨论】:

        猜你喜欢
        • 2021-07-24
        • 1970-01-01
        • 2011-08-18
        • 2013-01-18
        • 1970-01-01
        • 1970-01-01
        • 2020-10-05
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多