今天运行刚写的本地程序的时候发现偶发性的出现如下异常。
java.util.ConcurrentModificationException
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901)
at java.util.ArrayList$Itr.next(ArrayList.java:851)
at ys.manufacture.dip.etl.listener.TaskLogListener$1.run(TaskLogListener.java:31)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset$$$capture(FutureTask.java:308)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
问题分析
网上搜索了一下发现这个问题是因为对Vector、ArrayList在迭代的时候如果同时对其进行修改就会抛出java.util.ConcurrentModificationException异常。这个异常是因为迭代器遍历出现的,我使用的增强型for循环的方式,所以出现了这种问题。下面是我代码的主要部分:
TaskMonitorListener.java
这是一个每分钟执行的定时任务操作,并且对缓存中的List进行遍历操作,遍历查询数据并写入到指定的文件中。
for (String context : taskLog.getValue()) {
String[] taskLogKeys = taskLog.getKey().split(SymbolsConstants.COLON);
TaskMonitorUtil.writeLogFile(taskLogKeys[0], taskLogKeys[1], context);
}
JdbcSink.java
这里本质也是一个定时任务操作,会定时的每隔5秒从channel中拉取数据,并且写入到缓存的List集合中
TaskMonitorUtil.report(taskId, task.getTaskInstance().getTaskInstanceId(), "[jdbc sink]试运行结束!");
解决方案
改为使用普通for循环的方式就可以了
for (int i = 0; i < taskLog.getValue().size(); i++) {
String context = taskLog.getValue().get(i);
String[] taskLogKeys = taskLog.getKey().split(SymbolsConstants.COLON);
TaskMonitorUtil.writeLogFile(taskLogKeys[0], taskLogKeys[1], context);
}
再次运行,发现没有再报ConcurrentModificationException的错误了