我目前有一个简单的事件调度程序逻辑,它使用以下与侦听器列表配对的事件列表示例:
kotlin
val listenerMap: EnumMap<EventKey, MutableList<EventListener>> = EnumMap<EventKey::class.java)
它的作用如下:
对于每个
EventKey
表示应用程序内部的事件(可以是从NetworkDisconnected
to的任何IncorrectCredentials
事件),如果该列表不为空,则该事件用于遍历其各自的事件侦听器列表,并将相应的事件调用分派给每个侦听器。listenerMap
开始是空的,只有在添加了至少一个侦听器时才第一次填充每个侦听EventKey
器EventKey
,但是一旦在其中EventKey
创建了条目,listenerMap
它将不再被删除,只有它各自的侦听器列表将被改变(添加或删除的侦听器)。我从不迭代列表,我只使用以下列表方法:
List.add
和List.remove
. 我知道在内部(android 源列表内部)可能会发生迭代,但那部分从未由我完成,也没有任何形式的迭代。我什至不使用List.contains
.
我完全清楚,至少听众名单有风险ConcurrentModificationException
,我已经能够触发。
我现在的问题是我很困惑哪种预防方法ConcurrentModificationException
在确保它不会再次发生方面是最好的,并且在性能方面是最好的。
我有这个担心,因为这部分应用程序需要良好的性能。
以下是我在网上找到的与以下相关的解决方案的选项列表ConcurrentModificationException
:
- 利用
Collections.synchronizedMap(EnumMap<EventKey, MutableList<EventListener>>)
- 当需要
EnumMap<EventKey, MutableList<EventListener>>
对 进行任何访问时,每次对listenerMap
EnumMap
- 当需要
- 利用
Collections.synchronizedList(MutableList<EventListener>))
- 读取列表或修改列表时,每次访问
MutableList<EventListener>
都通过此方法完成
- 读取列表或修改列表时,每次访问
- 利用
CopyOnWriteArrayList
- 从我在网上找到的用户反馈来看,就性能而言,这似乎是一个非常昂贵的解决方案
- 利用
AtomicReference<MutableList<EventListener>>
- 不太确定这个,但我看到了很多关于使用
Atomic*
代替使用的建议synchronized(*)
- 不太确定这个,但我看到了很多关于使用
- 使用
synchronized(MutableList<EventListener>)
/locks
- 这是我想到的第一个,但我看到很多用户建议不要使用它,如果有其他更好的选择,比如使用
Atomic*
- 这是我想到的第一个,但我看到很多用户建议不要使用它,如果有其他更好的选择,比如使用
现在我更倾向于使用Collections.synchronizedList
,但我想知道是否有更好的方法来使用我所拥有的东西,只要ConcurrentModificationException
安全包含,并且当前性能尽可能好。
此外,如果除了我上面列出的方法之外还有其他方法可以做到这一点,如果您认为它们优于那些方法,请随时提出建议。
笔记
请不要建议使用库来解决这个问题,这不是这个问题的目的。我知道周围有很多基于事件的调度库,这不是寻找最佳库的问题,而是寻找解决我问题的最佳方法。