我有以下代码,它给出了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行是我将错误添加到列表的位置。
答案 0 :(得分:3)
ConcurrentModificationException
直接与同步或线程安全无关。多个线程会使此异常(见下文)的条件不可见,但也可能出现在一个线程中!
同步列表阻止您从未定义状态的多个线程访问列表。但是您仍然可以在修改列表时迭代元素。这将产生ConcurrentModificationException
。
在迭代过程中,您不得使用add()
,remove()
等修改列表。唯一有效的修改是使用Iterator
(remove()
)或ListIterator
(add()
和set()
)的方法!
答案 1 :(得分:1)
您尚未同步第三个列表successfullyExported
。
这无法解释修改unsuccessfullyExported
的例外情况,但我不相信这种情况真的发生了。它不可能。也许真正发生的事情是DoiPool或HandleSystemDoiAdministrator(无论它们是什么)也不同步。
答案 2 :(得分:0)
当迭代它时,用户必须手动同步返回的列表。
也许您真正需要的是CopyOnWriteArrayList
而不是?
编辑:抱歉,触发器有点快。仔细检查相关代码后,ConcurrentModificationException
AbstractMap
调用toString()
,toString()
只有一个显式调用handleSystemDoiAdministrator.updateDoiHandle( doi, url );
,而且只有{{1}}主动似乎是变异状态是这个{{1}}行,我认为潜在的原因可能隐藏在该类中的某个地方。因为它似乎是许多线程同时使用的Singleton。我会检查以确保它首先是线程安全的。