在Java内部类中安全实现观察者模式的关键是确保主题侧线程安全:使用CopyOnWriteArrayList管理观察者列表,避免内部类直接修改共享状态,通知时遍历快照而不阻塞注册/注销。

在 Java 内部类中安全实现观察者模式,关键不是“内部类本身能解决线程安全”,而是**如何让内部类作为观察者参与时,不破坏主题的线程安全性**。内部类(尤其是匿名或局部内部类)常用于简化监听器注册,但若主题的观察者列表操作未加保护,多线程下极易出现 ConcurrentModificationException 或漏通知等问题。
内部类作观察者时的典型风险
内部类本身没有线程安全属性,它只是语法糖——它能便捷访问外部类成员,但也容易因共享状态引发竞态:
- 多个线程同时调用
subject.addObserver(new MyObserver()),而主题内部用ArrayList存储观察者,未同步 → 注册失败或列表损坏 - 一个线程正在遍历通知观察者,另一个线程同时调用
removeObserver()→ 迭代器抛出并发修改异常 - 内部类持有外部类引用,若外部类状态被多线程修改(如共享字段),而内部类
update()方法直接读取该字段 → 读到脏数据或不一致状态
安全实现的三个核心要点
真正起作用的是主题(Subject)侧的设计,内部类只需配合即可:
-
用线程安全集合管理观察者:将
List<Observer>替换为CopyOnWriteArrayList。它允许并发读、写时复制底层数组,避免迭代时修改冲突,特别适合“读多写少”的观察者场景(注册/注销远少于通知) -
避免在内部类中修改共享状态:如果内部类需要响应事件并更新外部类字段,应通过同步块、
AtomicInteger等线程安全方式操作,而非直接赋值。例如:new Observer() { public void update(String msg) { synchronized(outerLock) { count++; } } } -
通知过程不阻塞注册/注销:使用
CopyOnWriteArrayList后,notifyObservers()可直接遍历快照,无需加锁;而add()和remove()本身已线程安全,无需额外同步
推荐写法示例(含内部类)
以下是一个简洁、线程安全的实现片段:
立即学习“Java免费学习笔记(深入)”;
// 主题类,内部使用 CopyOnWriteArrayList
public class EventSource { private final CopyOnWriteArrayList<Observer> observers = new CopyOnWriteArrayList<>(); private volatile String state; public void setState(String state) { this.state = state; notifyObservers(); } public void addObserver(Observer o) { observers.add(o); } public void removeObserver(Observer o) { observers.remove(o); } private void notifyObservers() { for (Observer o : observers) o.update(state); // 安全遍历快照 }}
// 使用匿名内部类注册观察者(线程安全)
EventSource source = new EventSource();source.addObserver(new Observer() { @Override public void update(String msg) { System.out.println("Received: " + msg); // 无共享写,天然安全 }});
替代方案:Lambda 更简洁且语义清晰
Java 8+ 中,用 Lambda 表达式代替匿名内部类,逻辑更轻量,也更容易规避状态误用:
- 避免了显式持有外部类引用带来的歧义
- 强制函数式风格,减少可变状态操作
- 与
CopyOnWriteArrayList配合,代码更简短安全
例如:source.addObserver(msg -> System.out.println("Lambda got: " + msg));


















