【问题标题】:What cause java.util.concurrentmodificationexception using Collections.synchronizedList?是什么导致 java.util.concurrentmodificationexception 使用 Collections.synchronizedList?
【发布时间】:2014-05-08 08:03:07
【问题描述】:

我有以下代码,它给出了 java.util.concurrentmodificationexception。

我不是线程方面的专家,但我认为如果我有一个同步列表,它应该是线程安全的......

编辑: 这是我的方法的完整代码。

@Override
    protected List< ExportSchedule > export( List< ExportSchedule > exportSchedules )
    {
        final HandleSystemDoiAdministrator handleSystemDoiAdministrator = HandleSystemDoiAdministratorFactory.getInstance();
        final List< ExportSchedule > successfullyExported = new ArrayList<>();
        final List<ExportError> unsuccessfullyExported = Collections.synchronizedList( new ArrayList<ExportError>() );

        ExecutorService executorService = Executors.newFixedThreadPool( 10 );

        for ( final ExportSchedule exportSchedule : exportSchedules )
        {
            executorService.execute( new Runnable() {
                public void run()
                {
                    String doi = exportSchedule.getDoi().getDoi();
                    String url = exportSchedule.getDoi().getUrl();

                    boolean success = handleSystemDoiAdministrator.updateDoiHandle( doi, url );

                    if ( success )
                    {
                        successfullyExported.add( exportSchedule );
                    }
                    else
                    {
                        if ( handleSystemDoiAdministrator.isWarn() )
                        {
                            DoiErrorHelper.persistExportError(
                                ExportInterface.HANDLE_SERVER,
                                doi,
                                "Warning: Error exporting DOI " + doi + " with URL " + url + " to Handle Server: "
                                        + handleSystemDoiAdministrator.getResponseOutcome().toString(),
                                exportSchedule.getDoi().getDoiPool() );
                        }
                        if ( handleSystemDoiAdministrator.isFatal() )
                        {


                            synchronized(unsuccessfullyExported) {
                            unsuccessfullyExported.add( DoiErrorHelper.createExportError( doi, "Fatal: Error exporting DOI " + doi + " with URL " + url + " to Handle Server: "
                                        + handleSystemDoiAdministrator.getResponseOutcome().toString(), null, new Date(), exportSchedule.getDoi().getDoiPool().getName(),
                                        exportSchedule.getDoi().getDoiPool().getDoiPrefix(), ExportInterface.HANDLE_SERVER ) );}
                        }
                    }
                }
            } );
        }

        executorService.shutdown();
        try
        {
            executorService.awaitTermination( 1, TimeUnit.MINUTES );
        }
        catch ( InterruptedException e )
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return successfullyExported;
    }

编辑 2:

这是错误:

    [exec]
     [exec] [#|2014-05-08T10:16:12.951+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=203;_ThreadName=Thread-2;|    at java.util.HashMap$HashIterator.nextEntry(HashMap.java:894)|
#]
     [exec]
     [exec] [#|2014-05-08T10:16:12.951+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=203;_ThreadName=Thread-2;|    at java.util.HashMap$EntryIterator.next(HashMap.java:934)|#]
     [exec]
     [exec] [#|2014-05-08T10:16:12.951+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=203;_ThreadName=Thread-2;|    at java.util.HashMap$EntryIterator.next(HashMap.java:932)|#]
     [exec]
     [exec] [#|2014-05-08T10:16:12.952+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=203;_ThreadName=Thread-2;|    at java.util.AbstractMap.toString(AbstractMap.java:518)|#]
     [exec]
     [exec] [#|2014-05-08T10:16:12.952+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=203;_ThreadName=Thread-2;|    at ch.ethz.id.wai.doi.export.handle.DoiExport2HSProcessing$1.r
un(DoiExport2HSProcessing.java:106)|#]
     [exec]
     [exec] [#|2014-05-08T10:16:12.952+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=203;_ThreadName=Thread-2;|    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoo
lExecutor.java:1145)|#]
     [exec]
     [exec] [#|2014-05-08T10:16:12.952+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=203;_ThreadName=Thread-2;|    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPo
olExecutor.java:615)|#]
     [exec]
     [exec] [#|2014-05-08T10:16:12.953+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=203;_ThreadName=Thread-2;|    at java.lang.Thread.run(Thread.java:722)|#]
     [exec]
     [exec] [#|2014-05-08T10:16:28.552+0200|INFO|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=157;_ThreadName=Thread-2;|0|#]
     [exec]
     [exec] [#|2014-05-08T10:16:31.221+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=222;_ThreadName=Thread-2;|Exception in thread "pool-41-thread-10" |#]
     [exec]
     [exec] [#|2014-05-08T10:16:31.223+0200|SEVERE|glassfish3.1.2|javax.enterprise.system.std.com.sun.enterprise.server.logging|_ThreadID=222;_ThreadName=Thread-2;|java.util.ConcurrentModificationException
     [exec]     at java.util.HashMap$HashIterator.nextEntry(HashMap.java:894)
     [exec]     at java.util.HashMap$EntryIterator.next(HashMap.java:934)
     [exec]     at java.util.HashMap$EntryIterator.next(HashMap.java:932)
     [exec]     at java.util.AbstractMap.toString(AbstractMap.java:518)
     [exec]     at ch.ethz.id.wai.doi.export.handle.DoiExport2HSProcessing$1.run(DoiExport2HSProcessing.java:106)
     [exec]     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
     [exec]     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
     [exec]     at java.lang.Thread.run(Thread.java:722)
     [exec] |#]

DoiExport2HSProcessing.java 是包含该方法的类,第 106 行是我将错误添加到列表的位置。

【问题讨论】:

  • 您确定这是对您的代码的准确摘要,并且没有其他任何东西同时使用exportSchedulesunsuccessfullyExported
  • @Boann 我用我的方法的完整代码编辑了我的问题。如您所见,没有其他东西使用这两个列表
  • 查看堆栈跟踪似乎concurrentmodificationexception 发生在map 而不是list。你显示的代码没有使用任何maps
  • 所有线程只使用handleSystemDoiAdministrator 的一个实例,这意味着其中的所有内容也应该是线程安全的。

标签: java multithreading synchronization


【解决方案1】:

ConcurrentModificationException 与同步或线程安全直接无关。多个线程将使此异常的条件(见下文)不可见,但它也可能发生在一个线程中!

同步列表可防止您从处于未定义状态的多个线程访问该列表。但是您仍然可以在修改列表时迭代元素。这将导致ConcurrentModificationException

不得在迭代过程中使用add()remove() 等修改列表。唯一有效的修改是使用Iteratorremove())或ListIteratoradd()set())的方法!

【讨论】:

  • 第一个说法不正确。已被其他线程修改的集合在被迭代时会抛出 CME。
  • 你没有,但是其他线程确实修改时也会出现这个异常。您能否更正您的帖子,以免读者感到困惑?
【解决方案2】:

你还没有同步第三个列表,successfullyExported

这无法解释修改unsuccessfullyExported 的异常,但我不相信这真的会发生。不可能。也许真正发生的事情是 DoiPool 或 HandleSystemDoiAdministrator(无论它们是什么)也没有同步。

【讨论】:

  • 目前success 总是假的,所以successfullyExported 是不同步的。不相关(以后想它会是:))。关于DoiPool和HandleSystemDoiAdministrator,看到它们是“简单”的对象,我只是在阅读它们(没有修改它们),这应该没有问题吗?
  • @Francesco 如果这是真的,那么您不可能遇到异常。
  • 这也是我的想法;),但我得到了问题中的错误(添加)
  • @Francesco 谢谢。和我想的一样。由于在 HandleSystemDoiAdministrator 中未同步使用共享 HashMap,您会收到 ConcurrentModificationException。我猜这是“响应结果”,同时由updateDoiHandle() 填充并由toString() 调用迭代。
【解决方案3】:

来自the documentation

用户在迭代返回的列表时必须手动同步它。

也许您真正需要的是CopyOnWriteArrayList

编辑:抱歉,触发有点快。在仔细检查了有问题的代码之后,由于ConcurrentModificationException 发生在AbstractMaptoString() 的调用上,并且只有一个对toString() 的显式调用,并且唯一似乎积极改变状态的地方是这个@ 987654329@ 行,我认为根本原因可能隐藏在该类中的某个地方。因为它似乎是一个被许多线程同时使用的单例。我会先检查以确保它是线程安全的。

【讨论】:

  • 他不是在迭代同步列表吗?
  • @Boann 哎呀。我已经更正了我的答案,可能会更有帮助。 :)
  • 这基本上就是我说的earlier
  • 那应该很准确吧? :)
猜你喜欢
  • 1970-01-01
  • 2013-09-18
  • 1970-01-01
  • 2017-02-04
  • 1970-01-01
  • 2010-12-31
  • 2013-03-10
  • 2011-03-12
相关资源
最近更新 更多