【死磕Java并发】—–Java内存模型之从JMM角度分析DCL
这篇讲的是Java并发编程中一个经典而隐蔽的陷阱——双重检查锁定(DCL)在实现单例模式时,看似高效完美,实则潜藏因指令重排序导致的对象未初始化即被引用的严重问题。 作者从一个常见的错误懒汉式单例写法入手,逐步推导到试图优化性能的DCL写法。其核心矛盾在于:对象实例化包含“分配内存”、“初始化对象”和“引用赋值”三个步骤,而JVM或CPU可能对后两步进行重排序。这就意味着,在多线程环境下,其他线程可能看到一个已完成引用赋值、但尚未完成初始化的对象“半成品”,导致程序行为不可预期。 文章进而给出了两种标准解决方案。一种是利用`volatile`关键字的内存屏障语义,禁止实例初始化步骤的重排序,从而确保对象完全构造完毕后对其他线程才可见。另一种则是利用类加载机制,通过静态内部类延迟初始化,借助JVM对类初始化过程加锁的保证,来实现线程安全的单例。后者巧妙地将同步问题委托给了JVM本身,代码也更为简洁。 理解DCL的问题根源及解决方案,对于掌握Java内存模型中多线程可见性与指令重排序的实际影响至关重要。