What cause java.util.concurrentmodificationexception using Collections.synchronizedList?

China☆狼群 提交于 2019-12-23 17:22:55

问题


I have the following code which gives a java.util.concurrentmodificationexception.

I'm not an expert working with threads, but I thought that if I have a synchronized list, it should be thread safe...

EDIT: This is the full code of my method.

@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;
    }

EDIT 2:

This is the error:

    [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 is the class containing the method and line 106 is where I add the error to the list.


回答1:


ConcurrentModificationException has nothing to do with synchronized or thread safety directly. Multiple threads will make the condition for this exception (see below) invisible but it can also occur with one thread!

The synchronized list prevents you from accessing the list from multiple threads in an undefined state. But you still can iterate the elements while modifying the list. This will result in an ConcurrentModificationException.

You must not modify the list using add(), remove() etc. during iterating it. The only valid modifications are using methods of the Iterator (remove()) or ListIterator (add() and set())!




回答2:


You have not synchronized the third list, successfullyExported.

That can't explain the exception from modifying unsuccessfullyExported, but I don't believe that's really happening. It can't be. Perhaps what's really happening is the DoiPool or HandleSystemDoiAdministrator (whatever they are) are also not synchronized.




回答3:


From the documentation:

It is imperative that the user manually synchronize on the returned list when iterating over it.

Maybe what you really need is a CopyOnWriteArrayList instead?

Edit: Sorry, was a bit quick on the trigger. After careful examination of the code in question, and since the ConcurrentModificationException happens on an AbstractMap call to toString() and there is only one explicit call to toString() and the only place that actively seems to mutate state is this handleSystemDoiAdministrator.updateDoiHandle( doi, url ); line, I'm thinking the underlying cause is probably hidden somewhere inside that Class. As it seems to be a Singleton being used by many threads at once. I would check to make sure that it was threadsafe first.



来源:https://stackoverflow.com/questions/23536074/what-cause-java-util-concurrentmodificationexception-using-collections-synchroni

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!