在 Java 中使用观察者模式(Observer Pattern)时,容易出现死锁或并发问题,通常不是模式本身的问题,而是通知机制 + 多线程 + 锁使用不当导致的。下面从原因 → 解决方案 → 示例系统说明。
典型死锁场景:
class Subject {
private final List<Observer> observers = new ArrayList<>();
private final Object lock = new Object();
void addObserver(Observer o) {
synchronized (lock) {
observers.add(o);
}
}
void notifyObservers() {
synchronized (lock) {
for (Observer o : observers) {
o.update(this); // ❌ 在锁内回调
}
}
}
}
class ObserverImpl implements Observer {
private final Subject subject;
public void update(Subject s) {
subject.addObserver(...); // ❌ 又去拿 subject 的锁
}
}
死锁原因:
Subject 锁update() 中又试图获取 Subject 锁先拷贝观察者列表,再在锁外通知
void notifyObservers() {
List<Observer> snapshot;
synchronized (lock) {
snapshot = new ArrayList<>(observers);
}
for (Observer o : snapshot) {
o.update(this); // ✅ 无锁
}
}
✅ 避免:
如果必须修改:
public void update(Subject s) {
executor.submit(() -> {
// 异步处理,不拿 subject 锁
});
}
避免自己加锁出错
private final CopyOnWriteArrayList<Observer> observers =
new CopyOnWriteArrayList<>();
✅ 优点:
ConcurrentModificationException彻底解耦,避免同步回调
subject.publishEvent(event); // 放入队列
观察者异步消费:
BlockingQueueEventBus(Guava / Spring)Reactor / RxJavaclass Subject {
private final List<Observer> observers =
new CopyOnWriteArrayList<>();
void add(Observer o) {
observers.add(o);
}
void notifyObservers() {
for (Observer o : observers) {
o.update(this);
}
}
}
✅ 无锁 ✅ 不会死锁 ⚠️ 写多读少时不合适
class Subject {
private final List<Observer> observers = new ArrayList<>();
private final Object lock = new Object();
void add(Observer o) {
synchronized (lock) {
observers.add(o);
}
}
void notifyAllObservers() {
List<Observer> copy;
synchronized (lock) {
copy = new ArrayList<>(observers);
}
for (Observer o : copy) {
o.update(this);
}
}
}
@Component
class MyObserver {
@EventListener
public void onEvent(MyEvent e) {
// 自动异步/同步
}
}
✅ 内建线程安全 ✅ 解耦彻底
synchronized 中调用外部方法?update() 中修改 Subject?观察者模式避免死锁的关键:
不在锁中回调 Observer,Observer 不直接操作 Subject,能用异步就用异步。
如果你有具体代码或并发场景(如多线程、UI、Spring),我可以帮你针对性改。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。