Jar*_*els 5 api synchronization listener thread-safety
我正在努力做出决定.我正在编写一个线程安全的库/ API.可以注册监听器,以便在发生有趣的事情时通知客户端.这两种实现中哪一种最常见?
class MyModule {
protected Listener listener;
protected void somethingHappens() {
synchronized(this) {
... do useful stuff ...
listener.notify();
}
}
}
Run Code Online (Sandbox Code Playgroud)
要么
class MyModule {
protected Listener listener;
protected void somethingHappens() {
Listener l = null;
synchronized(this) {
... do useful stuff ...
l = listener;
}
l.notify();
}
}
Run Code Online (Sandbox Code Playgroud)
在第一个实现中,在同步内通知侦听器.在第二种实现中,这是在同步之外完成的.
我觉得建议使用第二个,因为它减少了潜在的死锁空间.但我很难说服自己.
第二个实现的缺点是客户端可能会收到"不正确"的通知,如果它在l.notify()语句之前访问并更改了模块,则会发生这种情况.例如,如果它要求模块停止发送通知,则无论如何都会发送此通知.在第一个实现中不是这种情况.
非常感谢
这取决于您在方法中的何处获取侦听器、您有多少个侦听器、侦听器如何订阅/取消订阅
假设您的示例中只有一个侦听器,那么您可能最好对类的不同部分使用关键部分(或监视器),而不是锁定整个对象。
您可以拥有一把锁,用于在方法内执行特定于当前对象/任务的任务,并拥有一把锁用于侦听器订阅/取消订阅/通知(即确保侦听器在通知期间不会更改)。
我还会使用 ReadWriteLock 保护您的侦听器引用(单个侦听器或侦听器列表)
回复你的评论:
我认为你应该在解锁课程后通知听众。这是因为,该通知的结果可能会导致不同的线程尝试访问该类,但在某些情况下它可能无法做到这一点,从而导致死锁。
通知侦听器(如果像我所描述的那样受到保护)不应阻止任何需要该类功能的其他线程。最好的策略是创建特定于类状态的锁和特定于安全通知的锁。
如果您以挂起通知为例,这可能会被管理通知的锁所覆盖,因此,如果另一个线程“挂起”通知,则挂起将被处理或当前通知完成,如果另一个线程在正在处理任务并且发生通知,l.notify() 将不会发生。
Listener l = null;
synchronised(processLock_) {
... do stuff....
synchronised(notifyLock_) {
l = listener;
}
}
//
// current thread preempted by other thread that suspends notification here.
//
synchronised(notifyLock_) { // ideally use a readwritelock here...
l = allowNotify_ ? l: null;
}
if(l)
l.notify();
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
332 次 |
| 最近记录: |