Spring 批处理管理在每次执行后抛出 ConcurrentModificationException
Spring Batch Admin throws ConcurrentModificationException after every execution
随着我对它的深入了解,我发现我喜欢 spring 批处理管理应用程序。
但是,在每次作业执行后,我都会看到抛出此异常。
环境
OS: Windows 7
Java: jdk 1.8.0_25
Spring Batch Admin Sample version: 1.3.1
Spring version: 3.2.13 * stock 3.2.9 has a bug that causes other symptoms
Spring-batch version: 3.0.2
Pivotal tc version: 3.0 Developer Edition
IDE: STS 3.6.3
日志片段:
14:33:36.246 [pool-1-thread-1] ERROR o.s.s.s.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task.
java.util.ConcurrentModificationException: null
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) ~[na:1.8.0_25]
at java.util.ArrayList$Itr.remove(ArrayList.java:865) ~[na:1.8.0_25]
at org.springframework.batch.admin.service.SimpleJobService.removeInactiveExecutions(SimpleJobService.java:498) ~[spring-batch-admin-manager-1.3.1.MAXIS-MOD.jar:na]
at sun.reflect.GeneratedMethodAccessor196.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_25]
at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_25]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:64) ~[spring-context-3.2.13.RELEASE.jar:3.2.13.RELEASE]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:53) ~[spring-context-3.2.13.RELEASE.jar:3.2.13.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_25]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [na:1.8.0_25]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access1(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_25]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [na:1.8.0_25]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_25]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_25]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25]
我的代码没有触及spring批管理的核心,所以我有点困惑。
这还不是一个亮点,所以我愿意接受建议(包括最终贡献一个补丁)。
异常的原因是 org.springframework.batch.admin.service.SimpleJobService
的错误实现,至少在 1.3 中是这样。1.RELEASE:
private Collection<JobExecution> activeExecutions = Collections.synchronizedList(new ArrayList<JobExecution>());
public void removeInactiveExecutions() {
for (Iterator<JobExecution> iterator = activeExecutions.iterator(); iterator.hasNext();) {
JobExecution jobExecution = iterator.next();
...
if (!jobExecution.isRunning()) {
iterator.remove();
}
}
在 java.util.ArrayList
上调用 iterator.remove();
之后调用 iterator.getNext();
- 即使同步 - 也不是一个好主意...
我目前正在覆盖 Spring 批处理管理配置,使用我自己的 JobService 实现用于 id="jobService":
的 bean
META-INF\spring\batch\override\execution-context.xml
...
<bean id="jobService" class="com.foo.springbatch.MyPatchedSimpleJobServiceFactoryBean">
<property name="jobRepository" ref="jobRepository" />
<property name="jobLauncher" ref="jobLauncher" />
<property name="jobLocator" ref="jobRegistry" />
<property name="dataSource" ref="dataSource" />
</bean>
...
不确定为什么答案被接受。这是不正确的。 next() 的调用当然是在 hasNext() 之后。它是正确的。缺少同步以防止此方法的两个或多个计划调用可能发生冲突,以及 class 中其他位置的集合的其他修改。 Collections.synchronizedList(new ArrayList .. 他们拥有的是不够的。
刚遇到这个问题,一个简单的解决方法是将 org.springframework.batch.admin.service.SimpleJobService 中的代码更改为:
public void removeInactiveExecutions() {
**synchronized (activeExecutions) {**
for (Iterator<JobExecution> iterator = activeExecutions.iterator(); iterator.hasNext();) {
JobExecution jobExecution = iterator.next();
try {
jobExecution = getJobExecution(jobExecution.getId());
}
catch (NoSuchJobExecutionException e) {
logger.error("Unexpected exception loading JobExecution", e);
}
if (!jobExecution.isRunning()) {
iterator.remove();
}
}
**}**
}
上面的注释 ** 表示更改..
随着我对它的深入了解,我发现我喜欢 spring 批处理管理应用程序。
但是,在每次作业执行后,我都会看到抛出此异常。
环境
OS: Windows 7
Java: jdk 1.8.0_25
Spring Batch Admin Sample version: 1.3.1
Spring version: 3.2.13 * stock 3.2.9 has a bug that causes other symptoms
Spring-batch version: 3.0.2
Pivotal tc version: 3.0 Developer Edition
IDE: STS 3.6.3
日志片段:
14:33:36.246 [pool-1-thread-1] ERROR o.s.s.s.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task.
java.util.ConcurrentModificationException: null
at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:901) ~[na:1.8.0_25]
at java.util.ArrayList$Itr.remove(ArrayList.java:865) ~[na:1.8.0_25]
at org.springframework.batch.admin.service.SimpleJobService.removeInactiveExecutions(SimpleJobService.java:498) ~[spring-batch-admin-manager-1.3.1.MAXIS-MOD.jar:na]
at sun.reflect.GeneratedMethodAccessor196.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_25]
at java.lang.reflect.Method.invoke(Method.java:483) ~[na:1.8.0_25]
at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:64) ~[spring-context-3.2.13.RELEASE.jar:3.2.13.RELEASE]
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:53) ~[spring-context-3.2.13.RELEASE.jar:3.2.13.RELEASE]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_25]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) [na:1.8.0_25]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access1(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_25]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [na:1.8.0_25]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_25]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_25]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_25]
我的代码没有触及spring批管理的核心,所以我有点困惑。
这还不是一个亮点,所以我愿意接受建议(包括最终贡献一个补丁)。
异常的原因是 org.springframework.batch.admin.service.SimpleJobService
的错误实现,至少在 1.3 中是这样。1.RELEASE:
private Collection<JobExecution> activeExecutions = Collections.synchronizedList(new ArrayList<JobExecution>());
public void removeInactiveExecutions() {
for (Iterator<JobExecution> iterator = activeExecutions.iterator(); iterator.hasNext();) {
JobExecution jobExecution = iterator.next();
...
if (!jobExecution.isRunning()) {
iterator.remove();
}
}
在 java.util.ArrayList
上调用 iterator.remove();
之后调用 iterator.getNext();
- 即使同步 - 也不是一个好主意...
我目前正在覆盖 Spring 批处理管理配置,使用我自己的 JobService 实现用于 id="jobService":
的 beanMETA-INF\spring\batch\override\execution-context.xml
...
<bean id="jobService" class="com.foo.springbatch.MyPatchedSimpleJobServiceFactoryBean">
<property name="jobRepository" ref="jobRepository" />
<property name="jobLauncher" ref="jobLauncher" />
<property name="jobLocator" ref="jobRegistry" />
<property name="dataSource" ref="dataSource" />
</bean>
...
不确定为什么答案被接受。这是不正确的。 next() 的调用当然是在 hasNext() 之后。它是正确的。缺少同步以防止此方法的两个或多个计划调用可能发生冲突,以及 class 中其他位置的集合的其他修改。 Collections.synchronizedList(new ArrayList .. 他们拥有的是不够的。
刚遇到这个问题,一个简单的解决方法是将 org.springframework.batch.admin.service.SimpleJobService 中的代码更改为:
public void removeInactiveExecutions() {
**synchronized (activeExecutions) {**
for (Iterator<JobExecution> iterator = activeExecutions.iterator(); iterator.hasNext();) {
JobExecution jobExecution = iterator.next();
try {
jobExecution = getJobExecution(jobExecution.getId());
}
catch (NoSuchJobExecutionException e) {
logger.error("Unexpected exception loading JobExecution", e);
}
if (!jobExecution.isRunning()) {
iterator.remove();
}
}
**}**
}
上面的注释 ** 表示更改..