You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java中此段代码实现的double checked locking是否存在线程安全缺陷?

结论

你的判断完全正确,该双重检查锁定实现确实存在你描述的半初始化对象逃逸问题,同时还有额外的线程安全风险。

问题根因

  • 指令重排导致半初始化对象发布
    在Java内存模型中,new DoorControlManager(door) 操作会被拆分为三个独立步骤:分配对象内存空间、将内存地址赋值给对象引用、执行构造函数初始化字段。在没有正确同步的场景下,编译器和处理器允许对这三个步骤做重排序,可能出现「将地址赋值给引用」的操作跑到「构造函数执行」前面的情况。此时未完成初始化的对象会被提前放入HashMap,其他线程在同步块外执行containsKey判断时会认为对应实例已经存在,直接返回未初始化完成的对象,所有字段都为默认零值。
  • HashMap非线程安全带来额外风险
    代码中用到的HashMap本身不是线程安全实现,同步块外的containsKey操作执行时,如果刚好有其他线程在同步块内执行put操作触发HashMap扩容、结构调整,外部的读操作可能出现死循环、抛出异常、返回错误结果的问题。
  • 代码笔误
    方法入参名为door,但实际put、get时使用的键是slotId,代码无法直接编译通过,实际使用时需要先修正变量名一致性问题。

修复方案

如果是JDK8及以上版本,推荐直接用ConcurrentHashMap替代手动实现的DCL,简化实现且没有线程安全问题:

public class DoorControlManager {
    private static ConcurrentHashMap<Integer, DoorControlManager> mInstances = new ConcurrentHashMap<>();

    public static DoorControlManager getInstance(int door) {
        return mInstances.computeIfAbsent(door, DoorControlManager::new);
    }
    // 其余业务代码
}

如果必须保留原有DCL写法,可以将实例包装为带volatile修饰的对象避免重排序问题,同时把HashMap的所有读写操作都放在同步块内,或者直接替换为ConcurrentHashMap。

内容的提问来源于stack exchange,提问作者Willy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 00:57:00