适用于Java中事件侦听器的集合类

fin*_*nnw 13 java collections concurrency weak-references event-listener

相关: java是否有"LinkedConcurrentHashMap"数据结构?


我正在寻找一个集合类来保存对事件监听器的引用.

理想情况下,我希望该集合具有以下属性(按优先级顺序):

  1. 维护广告订单.较早的侦听器可能会取消该事件,从而阻止它被传递给稍后添加的侦听器.如果使用诸如HashSet迭代器可能以错误的顺序返回元素的类,这将会中断.
  2. 使用WeakReferences使得侦听器列表不会阻止侦听器被垃圾收集.
  3. 该集合是a Set,因此会自动删除重复项.
  4. Iterator是集合的线程安全快照,不受添加新侦听器的影响.还允许在多个线程上传递事件.(这不是必需的 - 我可以迭代一下该集的克隆.)

我知道有些类满足一些但不是所有这些标准.例子:

  • java.util.LinkedHashSet (#1和#3)
  • java.util.WeakHashMap,包裹着Collections.newSetFromMap(#2和#3)
  • javax.swing.event.EventListenerList (需要一些额外的同步)(#1和#4)
  • java.util.concurrent.CopyOnWriteArraySet (#1,#3和#4)

但#1和#2都没有.这样的类是否存在于某个库中?

kdg*_*ory 7

我首先要说的是,你有一些没有意义的要求.您正在寻找一个删除重复项并支持弱引用的集合,这表明听众可能会在不确定的时间出现和消失.但是,您希望维护插入顺序,并允许一个侦听器取消所有后续通知.对我来说,这听起来像是难以发现的错误的秘诀,我强烈建议重新考虑它.

也就是说,你有一个几乎驱动解决方案的要求:你不希望ConcurrentModificationException它来自普通的迭代器.这意味着您将不得不复制原始列表.在此过程中,您可以检查并删除空引用:

// the master list
List<WeakReference<MyListener>> _list = new ArrayList<WeakReference<MyListener>>();

// inside your send-notification method
List<MyListener> toNotify = new ArrayList<MyListener>(_list.size());
Iterator<WeakReference<MyListener>> itx = _list.iterator();
while (itx.hasNext())
{
    WeakReference<MyListener> ref = itx.next();
    MyListener lsnr = ref.get();
    if (lsnr != null)
        toNotify.add(lsnr);
    else
        itx.remove();
}

// now iterate "toNotify" and invoke the listeners
Run Code Online (Sandbox Code Playgroud)

你可能现在吓坏了,说"列表!这是一个线性数据结构!我不能使用它,插入是O(N)!"

嗯,是的,你可以.我不知道你打算有多少听众.但只要你<100(并且更可能<100,000),插入和删除的线性搜索的成本就不重要了.

从编码的角度来看,更有趣的是如何处理弱参考.你会注意到我在测试引用为null之前,明确地将它解引用到变量中.在处理引用对象时,这是非常重要的代码:尽管在两次调用之间收集引用的可能性极小get(),但这是可能的.

这让我了解了WeakReference自己.您需要创建自己的子类来覆盖委托给它的引用的方法equals()hashCode()方法.我以为我只是躺在这样的课堂上,但显然不是,所以会留给你实施.


Ole*_*boy 7

您可以使用WeakListeners(请参阅http://bits.netbeans.org/dev/javadoc/org-openide-util/org/openide/util/WeakListeners.html)和CopyOnWriteArraySet.

  1. remove(ListenerType listener)在事件源中实现方法.
  2. 在您的register(SomeListener listener)方法中,将WeakListener添加到集合中:

    listenerCollection.put((ListenerType)WeakListeners.create ( ListenerType.class, listener, this));

当从内存中删除真实侦听器时,将通知弱侦听器,并且它将取消注册自身.(这就是为什么它需要引用source(this)进行注册.)通过调用方法删除源来使用反射完成取消注册.