【问题标题】:How threadsafe is an EventListenerList?事件侦听器列表的线程安全性如何?
【发布时间】:2011-07-19 21:04:25
【问题描述】:

Javadoc for EventListenerLists 表示它们提供“一定程度的 MT 安全性(正确使用时)”。这意味着什么?我看到制作数组的副本可以保护您在开火时不会让东西自行移除,那么在什么情况下会失败?

更具体地说,我正在尝试构建一个 EventBus 来简化多线程应用程序中一些日益复杂的事件传递。我害怕如果多个线程试图触发/响应事件可能会发生什么,我也害怕通过阻塞机制来强制执行安全性,因为我的线程的目的是防止我的 UI 阻塞昂贵的任务。

【问题讨论】:

  • 实际上在我看来,就 CPU 访问重新排列而言,它不是线程安全的。不过,可能永远不会在 x86 上观察到它。
  • @bestsss:这不仅仅是你的意见,而是事实。 :-) 说真的,没有volatile 非常草率。 :-(

标签: java multithreading events event-handling


【解决方案1】:

它不是非常线程安全的。 :-((基于代码的OpenJDK 6 version。)

他们做对的事情:

  1. addremove 方法被标记为 synchronized,因此不会同时调用另一个方法
  2. 监听器列表数组永远不会被修改; addremove 总是为 listenerList 分配一个新数组

他们做错的事情(很遗憾):

  1. listenerList 字段不是 volatile
  2. getListenerList() 方法不是synchronized

也就是说,如果你在一个线程中调用addremove,然后在另一个线程中调用getListenerList,可能不会观察到变化,你可能仍然会取回旧版本的监听器列表.

【讨论】:

  • 您对更好的选择有什么建议吗?我正在考虑使用 ConcurrentSkipListSet,但我不确定这会处理你关于做错事情的两点,或者它会保持你关于正确完成事情的两点。
  • 实际上,我认为我可以忍受这种失败,如果添加时丢失一两个事件,或者删除时泄漏,它不会严重影响我的程序。谢谢。
  • @Dogmatixed:好吧,如果有一天你决定不能处理这个问题,CopyOnWriteArraySet 非常适合这种事情。
  • @Chris,虽然需要 volatile 它是“摇摆”的东西,所以 listenerList 字段将在某些时候可见(我忽略了该字段永久缓存到 CPU 寄存器中的选项)。所以最终会是一致的。但是,它不能保证: 但是,至少您永远不会观察到部分修改的侦听器列表。 除非 JVM 对 listenerList 字段使用内部函数。阅读器线程可以看到部分“添加”的侦听器,CPU 可以重新排列tmp[i] = t; tmp[i+1] = l; listenerList = tmp; 序列。所以它不是线程安全的。
  • @bestsss:是的,你完全正确。我忘记了重新排序(我不应该忘记)。我会将我的答案恢复到第一个修订版。 ;-)
猜你喜欢
  • 2018-01-29
  • 1970-01-01
  • 2014-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-27
相关资源
最近更新 更多