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

单例模式空值检查疑问:Google示例中双重校验的原因解析

为什么单例实现中要做两次 sInstance == null的空值检查?

这是**双重检查锁定(Double-Checked Locking)**的经典实现,咱们一步步说清楚为啥要两次检查:

  • 第一次锁外检查:性能优化
    当单例实例已经创建完成后,每次调用getInstance()都能直接跳过同步块,直接返回实例。如果没有这次检查,不管实例有没有创建,每次调用都得进入同步块等待锁,这在高并发场景下会带来很大的性能开销——毕竟锁的获取和释放是有成本的。

  • 第二次锁内检查:保证线程安全
    假设没有这次检查,当多个线程同时通过了第一次null检查(此时实例还没创建),它们会排队等待进入同步块。第一个线程进入后创建了实例,后面的线程拿到锁后,还是会执行buildDatabase()再次创建实例,这就彻底破坏了单例的唯一性。锁内的第二次检查能确保,只有第一个进入同步块的线程会创建实例,后续线程进来时看到实例已经存在,直接返回即可。

咱们结合你贴的代码再看就更清楚了:

public static AppDatabase getInstance(final Context context, final AppExecutors executors) { 
    if (sInstance == null) { // 第一次检查:快速返回已创建的实例,避免不必要的锁操作
        synchronized (AppDatabase.class) { 
            if (sInstance == null) { // 第二次检查:确保只有第一个线程能创建实例
                sInstance = buildDatabase(context.getApplicationContext(), executors); 
                sInstance.updateDatabaseCreated(context.getApplicationContext()); 
            } 
        } 
    } 
    return sInstance; 
}

另外补充个关键点:在Java中,为了避免指令重排序导致线程拿到未完全初始化的实例,sInstance变量需要被声明为volatile,不然双重检查锁定的逻辑可能会出现隐蔽的bug哦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 06:26:55