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

在Java单例模式中,能否通过同步getInstance()方法替代volatile?

单例模式:全同步方法实现 vs 双重检查锁实现

能不能用全同步方法替代双重检查锁(去掉volatile)?

可以。把整个getInstance()设为同步方法后,不需要volatile也能保证单例的正确性,但会带来明显的性能问题。

先给出全同步方法的实现代码:

public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public synchronized static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

两种实现的执行过程差异

1. 锁粒度与性能表现

  • 双重检查锁(DCL):只有第一次初始化实例的过程会进入同步块,后续所有调用直接返回已初始化的instance,完全不需要竞争锁。在高并发场景下,这种实现的性能开销极低。
  • 全同步方法:**每次调用getInstance()**都必须先获取Singleton.class的内置锁,哪怕实例已经初始化完成。大量并发线程会因为等待锁而阻塞,性能损耗非常大。

2. 内存可见性的保障逻辑

  • DCL:依赖volatile关键字的内存屏障特性,禁止instance = new Singleton()这行代码的指令重排,确保对象完全初始化后才会被其他线程读取,同时保证instance变量的读写操作在多线程间的可见性。
  • 全同步方法:依赖synchronized的内置锁机制——线程进入同步方法时,会强制从主内存刷新变量到工作内存;退出同步方法时,会把工作内存的变量写回主内存,同时禁止同步块内的指令重排。这就保证了即使没有volatile,其他线程也能看到完全初始化的instance。

3. 具体执行流程

  • DCL流程:
    1. 线程调用getInstance(),先无锁检查instance是否为null;
    2. 如果为null,竞争Singleton.class的锁;
    3. 获取锁后再次检查instance(防止多个等待锁的线程重复初始化);
    4. 创建实例后释放锁;
    5. 后续线程调用时,直接读取非null的instance返回,全程无锁。
  • 全同步方法流程:
    1. 任何线程调用getInstance(),必须先获取Singleton.class的锁;
    2. 获取锁后检查instance是否为null,创建实例或直接返回;
    3. 释放锁,下一个等待锁的线程重复上述步骤。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.21 23:33:16