单例模式 双检测问题请教

2022-04-11 09:29:02 +08:00
 followyourheart
public class Singleton {

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

uniqueInstance = new Singleton() 这行代码虽然会发生指令重排序, 但 synchronized 代码块已经加锁了,每次只有一个线程进入代码块,为啥还要加 volatile ?

3226 次点击
所在节点    Java
31 条回复
BQsummer
2022-04-11 13:04:38 +08:00
@Suddoo 自动挡汽车指的是什么
git00ll
2022-04-11 13:51:56 +08:00
a 线程使用赋值语句赋值后,b 线程可能看不到
crackhopper
2022-04-11 13:57:28 +08:00
每次看到 volatile 就头疼。C++和 Java 的 volatile 还不一样。
liudaolunhuibl
2022-04-11 13:58:51 +08:00
@BQsummer 用枚举吧,话说这种手写单例模式的还怎么见过,一般你需要某个类单例就把它交给他 spring 就好了
chengyiqun
2022-04-11 14:10:37 +08:00
推荐用静态内部类的写法代替这种写法, 或者用枚举, 最好用 spring 直接管理.
ligiggy
2022-04-11 14:24:05 +08:00
@crackhopper 哈哈哈,太经典了
quicksand
2022-04-11 14:39:50 +08:00
zhady009
2022-04-11 14:58:19 +08:00
要延迟加载用内部静态类的方式就好了 这种写法不知道多少年前的
如果不用延迟加载用 static final 或者直接 enum
MakHoCheung
2022-04-11 15:28:10 +08:00
同意 25 楼,与其深究这种容易出问题需要了解底层的方式,还不如去掌握没问题的方式
Red998
2022-04-15 16:45:59 +08:00
是对象初始化有几个步骤、申请内存--初始化--赋值--返回内存引用地址 。多线程情况下可能会存在 获取半初始化对象 。所有才需要 volatile 防止指令冲排序 至于为什么 cpu 指令会这样。个人觉得效率高吧。无论怎么样执行最后都是返回一个对象引用地址。 不过话又说回来 我真没看到现在有这么用 。一般的单例用的多也没啥大问题。非要完美一点 我觉得那个枚举方式就很好
goalidea
2022-12-03 18:39:08 +08:00
没有必要搞这么细,这也就面试中可能会问一问,工作中都是懒汉,不然就内部类实现

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/846190

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX