StringBuffer 与观察者模式无关,它仅提供字符串操作的线程安全,不参与观察者注册、遍历或通知逻辑;真正需同步的是观察者列表及通知过程。

StringBuffer 在实现观察者模式时并不承担同步职责,也不参与观察者模式的协作逻辑。它既不是该模式的组成部分,也不能替代线程协调机制。
StringBuffer 和观察者模式本质无关
观察者模式关注的是对象间一对多的通知关系:当被观察者状态改变,自动触发所有已注册观察者的回调。Java 传统实现依赖 Observable(已弃用)或自定义主题/监听器接口,核心在于:
- 注册与移除观察者
- 状态变更检测
- 遍历通知(通常需保证遍历时不被并发修改)
而 StringBuffer 只是一个线程安全的可变字符串容器,它的 synchronized 方法仅保障自身字符数组操作的原子性(如 append()、length()),不涉及观察者注册表的读写保护,也不管理通知流程的线程安全。
若在观察者实现中误用 StringBuffer 的典型风险
假设你用 StringBuffer 存储日志消息,并在 notifyObservers() 中拼接内容:
Java Maven 项目审查工作流的通用输入处理。当 Java Maven 项目以 ZIP压缩包或 GitLab 仓库 URL 形式提供且需要...时使用。
立即学习“Java免费学习笔记(深入)”;
public class LogSubject extends Observable {
private final StringBuffer logBuffer = new StringBuffer();
public void addLog(String entry) {
logBuffer.append(entry).append("\n"); // ✅ 线程安全
setChanged();
notifyObservers(); // ❌ 但 notifyObservers() 本身非线程安全
}
}问题在于:
-
logBuffer.append()是安全的,但notifyObservers()内部遍历observers列表时若被其他线程修改(如同时调用deleteObserver()),会抛ConcurrentModificationException -
StringBuffer并未保护observers这个Vector(旧版Observable使用)或你自定义的List<Observer>,这些结构仍需额外同步
真正需要同步的地方在哪里?
| 组件 | 是否需同步 | 说明 |
|---|---|---|
StringBuffer 字符拼接 |
✅ 自带同步 | 仅限其自身方法调用,如 append()、toString()
|
观察者列表(如 List<Observer>) |
✅ 必须手动同步 | 添加、删除、遍历都可能并发,建议用 CopyOnWriteArrayList 或 synchronized 块 |
notify 逻辑整体(检查+遍历+调用) |
✅ 推荐原子化 | 避免“检查后使用”竞态,例如先 isEmpty() 再 forEach(),中间可能被清空 |
更合理的做法
- 日志拼接用
StringBuffer或StringBuilder(单线程场景更推荐后者) - 观察者管理用线程安全集合:
private final List<Observer> observers = new CopyOnWriteArrayList<>();
- 通知过程无需锁整个
StringBuffer,而是保护共享状态变更和通知动作:public void notifyAllObservers(String message) { // message 已由 StringBuilder/StringBuffer 拼好,转为不可变 String String finalMsg = message.toString(); // 安全遍历(CopyOnWriteArrayList 天然支持) observers.forEach(observer -> observer.update(finalMsg)); }
StringBuffer 的同步能力仅止于字符串内容操作,它不能让观察者模式“自动线程安全”。把同步责任错配给它,反而掩盖了真正需要加锁的协作点。

















