【发布时间】:2019-02-14 23:43:47
【问题描述】:
我使代码与 OpenJDk8 兼容,并注意到有时跟随 sn-ps 会引发 ConcurrentModificationException。
代码在一个线程中执行。
list = new ArrayList<>();
list.addAll(newElements);
list.stream().parallel().forEach(o -> {});
当流线程在它们之间拆分列表时,ForkJoin 会引发异常。 片刻之后,我认为默认情况下这是合理的行为(不同步,简单集合)流线程不是新的,它们从池中使用(它们可以看到处于不一致状态的列表),但是在迭代之前复制集合看起来不太好。
我还没有发现这方面的错误,所以我问这个问题Java内存模型对这个案例的看法是什么?
顺便说一句,要提交 OJDK 错误,您必须是开发人员。
java.util.ConcurrentModificationException: java.util.ConcurrentModificationException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at java.util.concurrent.ForkJoinTask.getThrowableException(ForkJoinTask.java:593)
at java.util.concurrent.ForkJoinTask.reportException(ForkJoinTask.java:677)
at java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:735)
at java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:160)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:174)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:583)
at scheduler.JobScheduleUpdater.fetchJobSchedules(JobScheduleUpdater.java:118)
at scheduler.JobScheduleUpdater.processOneUpdate(JobScheduleUpdater.java:102)
at
scheduler.JobScheduleUpdater.execute(JobScheduleUpdater.java:81)
at scheduler.JobScheduleUpdater$$EnhancerByMockitoWithCGLIB$$ccd35a20.CGLIB$execute$11(<generated>)
at scheduler.JobScheduleUpdater$$EnhancerByMockitoWithCGLIB$$ccd35a20$$FastClassByMockitoWithCGLIB$$bf9de679.invoke(<generated>)
at org.mockito.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:216)
at org.powermock.api.mockito.repackaged.DelegatingMockitoMethodProxy.invokeSuper(DelegatingMockitoMethodProxy.java:20)
at org.mockito.internal.invocation.realmethod.DefaultRealMethod.invoke(DefaultRealMethod.java:21)
at org.mockito.internal.invocation.realmethod.CleanTraceRealMethod.invoke(CleanTraceRealMethod.java:30)
at org.mockito.internal.invocation.InvocationImpl.callRealMethod(InvocationImpl.java:112)
at org.mockito.internal.stubbing.answers.CallsRealMethods.answer(CallsRealMethods.java:41)
at org.mockito.internal.handler.MockHandlerImpl.handle(MockHandlerImpl.java:93)
at org.mockito.internal.handler.NullResultGuardian.handle(NullResultGuardian.java:29)
at org.mockito.internal.handler.InvocationNotifierHandler.handle(InvocationNotifierHandler.java:38)
at org.powermock.api.mockito.repackaged.MethodInterceptorFilter.intercept(MethodInterceptorFilter.java:60)
at scheduler.JobScheduleUpdater$$EnhancerByMockitoWithCGLIB$$ccd35a20.execute(<generated>)
at commons.util.service.ShutdownCapableThread.run(ShutdownCapableThread.java:74)
at scheduler.JobScheduleUpdater$$EnhancerByMockitoWithCGLIB$$ccd35a20.CGLIB$run$15(<generated>)
at scheduler.JobScheduleUpdater$$EnhancerByMockitoWithCGLIB$$ccd35a20$$FastClassByMockitoWithCGLIB$$bf9de679.invoke(<generated>)
at org.mockito.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:216)
at org.powermock.api.mockito.repackaged.DelegatingMockitoMethodProxy.invokeSuper(DelegatingMockitoMethodProxy.java:20)
at org.mockito.internal.invocation.realmethod.DefaultRealMethod.invoke(DefaultRealMethod.java:21)
at org.mockito.internal.invocation.realmethod.CleanTraceRealMethod.invoke(CleanTraceRealMethod.java:30)
at org.mockito.internal.invocation.InvocationImpl.callRealMethod(InvocationImpl.java:112)
at org.mockito.internal.stubbing.answers.CallsRealMethods.answer(CallsRealMethods.java:41)
at org.mockito.internal.handler.MockHandlerImpl.handle(MockHandlerImpl.java:93)
at org.mockito.internal.handler.NullResultGuardian.handle(NullResultGuardian.java:29)
at org.mockito.internal.handler.InvocationNotifierHandler.handle(InvocationNotifierHandler.java:38)
at org.powermock.api.mockito.repackaged.MethodInterceptorFilter.intercept(MethodInterceptorFilter.java:60)
at scheduler.JobScheduleUpdater$$EnhancerByMockitoWithCGLIB$$ccd35a20.run(<generated>)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.util.ConcurrentModificationException
at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1388)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:291)
at java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:731)
at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
【问题讨论】:
-
上面是你实现的代码吗?这会引发编译器错误。
-
这看起来很奇怪。 A Minimal, Complete, and Verifiable example,好吗?此外,如果我们需要运行示例 50 次才能看到错误(存在
for循环)。 -
我无法复制。尝试了从 1 到 300 000 个元素的不同列表。
-
@Holger 如果
PrintStream没有锁定用于访问控制台的系统资源。尽管我意识到这是一个无用的假设,但经过进一步研究 -
@MTCoster 那么,您可能会遇到
PrintStream及其内部使用的资源的问题,但不会遇到不相关的ArrayList之外的问题。
标签: java multithreading thread-safety java-stream