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

StringBuffer 在实现观察者模式时并不承担同步职责,也不参与观察者模式的协作逻辑。它既不是该模式的组成部分,也不能替代线程协调机制。
StringBuffer 和观察者模式本质无关
观察者模式关注的是对象间一对多的通知关系:当被观察者状态改变,自动触发所有已注册观察者的回调。Java 传统实现依赖 Observable(已弃用)或自定义主题/监听器接口,核心在于:
- 注册与移除观察者
- 状态变更检测
- 遍历通知(通常需保证遍历时不被并发修改)
而 StringBuffer 只是一个线程安全的可变字符串容器,它的 synchronized 方法仅保障自身字符数组操作的原子性(如 append()、length()),不涉及观察者注册表的读写保护,也不管理通知流程的线程安全。
你接手一个需求时,是不是经常这样:"改一个小字段 → 结果把不相关的代码也改了"、"需求说得很模糊 → 做着做着发现跑偏了"、"数据库加个字段 → 上线才发现漏了数据兼容"、"做了个新功能 → 一个月后自己都忘了当时怎么设计的"、"写到一半被中断 → 再回来不知道从哪继续";这个 Skill 就是专门解决这些问题的。 它会自动探测你的项目环境(JDK、Spring Boot、ORM、数据库、前端框架),记在
若在观察者实现中误用 StringBuffer 的典型风险
假设你用 StringBuffer 存储日志消息,并在 notifyObservers() 中拼接内容:
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></observer>,这些结构仍需额外同步
真正需要同步的地方在哪里?
| 组件 | 是否需同步 | 说明 |
|---|---|---|
StringBuffer 字符拼接 |
✅ 自带同步 | 仅限其自身方法调用,如 append()、toString()
|
观察者列表(如 List<observer></observer>) |
✅ 必须手动同步 | 添加、删除、遍历都可能并发,建议用 CopyOnWriteArrayList 或 synchronized 块 |
notify 逻辑整体(检查+遍历+调用) |
✅ 推荐原子化 | 避免“检查后使用”竞态,例如先 isEmpty() 再 forEach(),中间可能被清空 |
更合理的做法
- 日志拼接用
StringBuffer或StringBuilder(单线程场景更推荐后者) - 观察者管理用线程安全集合:
private final List<observer> observers = new CopyOnWriteArrayList();</observer>
- 通知过程无需锁整个
StringBuffer,而是保护共享状态变更和通知动作:public void notifyAllObservers(String message) { // message 已由 StringBuilder/StringBuffer 拼好,转为不可变 String String finalMsg = message.toString(); // 安全遍历(CopyOnWriteArrayList 天然支持) observers.forEach(observer -> observer.update(finalMsg)); }
StringBuffer 的同步能力仅止于字符串内容操作,它不能让观察者模式“自动线程安全”。把同步责任错配给它,反而掩盖了真正需要加锁的协作点。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










