stringbuffer的复合操作不安全,因其单个方法虽同步但锁独立释放,导致“检查+修改”间存在竞态窗口;需用synchronized(sb)包裹整个逻辑块保障原子性,或改用threadlocal等无锁设计。

StringBuffer 本身不保证复合操作的原子性,它只对单个方法调用(如 append()、length()、delete())做同步保护。要让“检查+修改”这类多步逻辑真正线程安全,必须手动加锁。
为什么 StringBuffer 的复合操作不安全
因为每个 synchronized 方法都是独立获取和释放锁的。例如:
-
sb.length()执行完后立刻释放锁 - 紧接着
sb.append("x")又重新申请锁 - 两个动作之间存在时间窗口,其他线程可能插入操作,导致状态不一致
如何手动保障复合操作原子性
用 synchronized(sb) 显式包裹整个逻辑块,确保从检查到修改全程持有同一把锁:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
- 正确写法:
synchronized (sb) { if (sb.length() - 适用于所有“先读再写”的场景:比如判空后
clear()、根据substring()结果决定是否insert() - 锁对象必须是同一个 StringBuffer 实例,不能换成别的引用
哪些操作属于典型复合逻辑
以下常见组合都需显式同步,否则存在竞态风险:
if (sb.length() == 0) sb.append("default");if (sb.indexOf("key") >= 0) sb.replace(...);char c = sb.charAt(0); sb.setCharAt(0, 'X');- 连续多次
append()并依赖中间长度判断
替代思路:减少对复合操作的依赖
比起硬套 synchronized 块,更推荐从设计上规避:
- 用 ThreadLocal
让每个线程独占拼接器,完全避开共享和锁 - 各线程生成字符串片段,最后由单一线程合并(如用
Collectors.joining()) - 若只是日志或聚合类场景,考虑无锁队列 + 异步刷写,而非强一致性拼接
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










