【发布时间】:2016-09-05 10:09:57
【问题描述】:
有一个 mEventMap 来保存不同事件的监听器,并有 addListener() 来注册事件监听器,removeListener() 和 dispatchEvent() 到注册的监听器。
public void addListener(EventListener listener) {
synchronized (mEventMap) {
List<WeakReference<EventListener<Event>>> listeners = mEventMap.get(listener.mEventClass);
WeakReference<EventListener<Event>> listenerRef = new WeakReference<>(
(EventListener<Event>) listener)
…
listeners.add(listenerRef);
…
}
}
public void removeListener(EventListener listener) {
synchronized (mEventMap) {
List<WeakReference<EventListener<Event>>> listeners = mEventMap.get(listener.mEventClass);
…
if (contains(listeners, listener)) {
doRemove(listeners, listener);
}
…
}
}
public boolean dispatchEvent(Event event) {
synchronized (mEventMap) {
List<WeakReference<EventListener<Event>>> listeners = mEventMap.get(event.getClass());
ListIterator<WeakReference<EventListener<Event>>> listenerIterator = listeners.listIterator(listeners.size());
…
while (listenerIterator.hasPrevious()) {
WeakReference<EventListener<Event>> listenerItem = listenerIterator.previous();
EventListener<Event> listenerRef = listenerItem.get();
if (listenerRef != null) {
listenerRef.onEvent(event);
} else {
listenerIterator.remove();
}
}
…
}
用例
EventListener<Event> mEventListener = new EventListener<Event>(
Event.class) {
@Override
public boolean onEvent(Event event) {
eMgr.removeListener(mEventListener);
// do something
}
};
addEventListener(mEventListener);
在 dispatchEvent() 中,当它在循环中时, removeListener() 被调用并在 listenerItem = listenerIterator.previous(); 处引发 ConcurrentModificationException;
问题:在有人迭代时,避免因 mEventMap 数据更改而导致崩溃的最佳方法是什么。
【问题讨论】:
-
一种方法是复制没有要删除的元素的列表...例如 CopyOnWriteArrayList
-
首先,对听众持有弱引用的想法是自取其辱的完美方式。这需要其他人对听众有强烈的参考,以防止听众的虚假消失。在通常的应用程序设计中,没有人持有此类必需的引用,并且匿名侦听器实例是常态。然后,一旦你放弃了弱引用的想法,看看
AWTEventMulticaster背后的设计模式,它提供了一种强大的事件传递方式,不受中间添加和删除的影响(无需克隆列表)。
标签: java multithreading event-handling