我应该同步监听器通知吗?

Jap*_* D. 3 java synchronized locks

我总是非常犹豫要把我的锁公开,让它们公开.我总是试图将锁限制在我的实现中.我相信,不这样做是一个僵局的秘诀.

我有以下课程:

class SomeClass {
    protected ArrayList<Listener> mListeners = new ArrayList<Listener>();

    protected void addListener(Listener listener) {
        synchronized (mListeners) {
            mListeners.add(listener);
        }
    }

    protected void removeListener(Listener listener) {
        synchronized (mListeners) {
            mListeners.remove(listener);
        }
    }

    ...
}
Run Code Online (Sandbox Code Playgroud)

当SomeClass想要通知他的听众时,你会这样做:

    synchronized (mListeners) {
        for (Listener l : mListeners) {
             l.event();
        }
    }
Run Code Online (Sandbox Code Playgroud)

要么

    Listener[] listeners = null;

    synchronized (mListeners) {
        listeners = mListeners.toArray();
    }
    for (Listener l : listeners) {
        l.event();
    }
Run Code Online (Sandbox Code Playgroud)

我会选择第二种选择.缺点是听众可以获得活动,即使他们已经取消注册.好处是,一个侦听器calllback正在等待的线程,当他想取消注册一个监听器时,它不会遇到死锁.我认为好处比下行更重要,可以很容易地记录下来.

所以这里的问题基本上是:你会暴露你的锁吗?

我的问题不是你选择一个简单的ArrayList,LinkedList,ConcurrentLinkedQueue,CopyOnWriteArrayList,......!您是否会介意监听器是否可以在未注册时收到通知.无论你是否将锁打开,或不是.这是关于避免死锁.

请分享你的想法.谢谢!

Eri*_*son 7

使用a CopyOnWriteArrayList作为侦听器数组.

这非常适合不经常更改的侦听器阵列.当您遍历它们时,您将遍历底层数组.使用a CopyOnWriteArrayList,每次修改时都会复制此数组.所以在迭代时不需要与它同步,因为每个底层数组都保证是静态的,甚至超过它在其中的使用CopyOnWriteArrayList.

由于CopyOnWriteArrayList也是线程安全的,因此您无需同步添加和删除操作.

宣言:

private final CopyOnWriteArrayList<Listener> listeners;
Run Code Online (Sandbox Code Playgroud)

事件触发器:

for (Listener l: this.listeners) {
  l.event();
}
Run Code Online (Sandbox Code Playgroud)