线程安全组件组合不等于业务整体线程安全,因“读-判-改”等多步操作存在竞态条件,共享状态未隔离会导致隐式耦合,弱一致性迭代器和不安全构造过程也会破坏业务语义。

把多个线程安全的组件(比如 AtomicInteger、ConcurrentHashMap)拼在一起,并不自动让整个业务逻辑变线程安全。这是并发编程中最隐蔽也最常被忽视的问题之一——组合安全 ≠ 整体安全。
原子操作不等于原子业务
单个操作线程安全,不代表多个操作连起来也安全。例如:
-
AtomicInteger.get()和AtomicInteger.incrementAndGet()各自都是原子的 - 但写成
if (counter.get() 就不是原子的——两个线程可能同时读到9,都通过判断,都执行自增,最终变成11而非预期的10
这种“读-判-改”三步组合,本质是竞态条件,必须用锁、CAS循环或更高层的原子复合方法(如 updateAndGet 配合函数式逻辑)来兜底。
共享状态未隔离导致隐式耦合
即使每个字段都用线程安全类型,只要它们共同支撑一个业务不变量,就仍需同步。例如:
- 用
AtomicInteger balance和ConcurrentMap管理账户余额与转账记录transfers - 执行“扣款+记账”时,若不加统一锁或事务性协调,可能出现:余额已扣但记录未写入,或记录写了但余额没扣
- 外部观察者看到的是不一致的中间态,破坏业务语义(如“钱少了但查不到去向”)
迭代与修改的弱一致性陷阱
像 ConcurrentHashMap 或 CopyOnWriteArrayList 提供弱一致性迭代器,适合“读多写少”,但不适合强一致性校验场景:
-
map.forEach((k,v) -> process(k,v))过程中,其他线程可能正在修改 map - 迭代器不会抛
ConcurrentModificationException,但可能漏掉新 entry、重复处理旧 entry,或读到部分更新的 value - 若业务逻辑依赖“遍历期间集合全貌不变”(如生成对账快照),就必须显式加锁或使用
computeIfPresent等原子批量操作
构造过程本身可能不安全
对象创建阶段常被忽略——即使内部字段全用线程安全类型,若初始化逻辑未同步,仍可能发布未完全构造的对象:
- 静态工厂方法返回含多个
AtomicReference的配置类,但构造函数中先赋值 A 字段、再赋值 B 字段 - 另一个线程在构造中途拿到引用,读到 A 已设、B 仍为 null,触发 NPE 或逻辑错乱
- 解决方式:用
final字段 + 安全构造(JVM 保证 final 字段的正确发布),或延迟初始化时加双重检查锁










