我正在测试一个事件系统,我正在为一个项目编写。在上述项目和测试中,我不接触线程。从字面上讲,我不创建线程,也不使用线程做任何事情。然而,我得到了一个ConcurrentModificationException。
据我所知,在其他情况下,可能会引发此异常。来自CME JavaDoc:
请注意,此异常并不总是指示对象已被不同线程并发修改。如果单个线程发出一系列违反对象契约的方法调用,则该对象可能会抛出此异常。
这是我的测试代码:
TestListener test = new TestListener();
Assert.assertTrue(evtMgr.register(test));
Assert.assertFalse(testBool);
evtMgr.fire(new QuestStartEvent(null));
Assert.assertTrue(testBool);
testBool = false;
evtMgr.unregister(test);
evtMgr.fire(new QuestStartEvent(null));
Assert.assertFalse(testBool);EventManager看起来是这样的:
public boolean register(Listener listener) {
return listeners.add(new ListenerHandle(listener));
}
public void unregister(Listener listener) {
listeners.stream().filter((l) -> l.getListener() == listener)
.forEach(listeners::remove);
}
public <T extends Event> T fire(T event) {
listeners.forEach((listener) -> listener.handle(event));
return event;
}ConcurrentModificationException在.forEach(listeners::remove);的位置
ListenerHandle看起来是这样的:
private final Listener listener;
private final Map<Class<? extends Event>, Set<MethodHandle>> eventHandlers;
public ListenerHandle(Listener listener) {
this.listener = listener;
this.eventHandlers = new HashMap<>();
for (Method meth : listener.getClass().getDeclaredMethods()) {
EventHandler eh = meth.getAnnotation(EventHandler.class);
if (eh == null || meth.getParameterCount() != 1) {
continue;
}
Class<?> parameter = meth.getParameterTypes()[0];
if (!Event.class.isAssignableFrom(parameter)) {
continue;
}
Class<? extends Event> evtClass = parameter.asSubclass(Event.class);
MethodHandle handle = MethodHandles.lookup().unreflect(meth);
Set<MethodHandle> handlers = eventHandlers.get(evtClass);
if (handlers == null) {
handlers = new HashSet<>();
eventHandlers.put(evtClass, handlers);
}
handlers.add(handle);
}
}
public void handle(Event event) {
Class<? extends Event> clazz = event.getClass();
Set<MethodHandle> handles = eventHandlers.get(clazz);
if (handles == null || handles.isEmpty()) {
return;
}
for (MethodHandle handle : handles) {
handle.invoke(listener, event);
}
}(为了提高可读性,尝试捕获量)
以及堆栈跟踪:
java.util.ConcurrentModificationException
at java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1545)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:512)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:502)
at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
at EventManager.unregister(EventManager.java:54)(第54行是.forEach(listeners::remove);)
发布于 2014-09-14 11:51:05
您将得到一个并发修改异常,因为您在对集合进行迭代的同时对它进行修改。而不是
listeners.stream().filter((l) -> l.getListener() == listener)
.forEach(listeners::remove);您应该使用传统的基于Iterator的成语,并在迭代器上而不是在集合上调用remove(),或者首先迭代来收集要删除的对象集,然后在初始迭代完成后一次删除它们:
listeners.removeAll(
listeners.stream().filter((l) -> l.getListener() == listener)
.collect(Collectors.toList()));迭代器方法可能更有效。
https://stackoverflow.com/questions/25832790
复制相似问题