双重检查单例模式,单例对象为何要加上volatile关键字?

https://www.cnblogs.com/damonhuang/p/5431866.html

java单例模式与线程安全_java单例模式线程安全_Tifkingsly的博客-CSDN博客

代码:

class Singleton{
    private volatile static Singleton instance = null;
    
    private Singletion{}

    public static Singleton getInstance(){
        if(instance==null){                        //#1
            synchronized(Singleton.class){         //#2
                if(instance==null){                //#3
                    instance = new Singletion();   //#4
                }else{
                    System.out.println("test");    //#5
                }
            }
        }
        return instance;
    }

}

单例对象为何要加上volatile关键字?有如下两方面原因:

(1)保证可见性:

如果"private static Singleton instance = null;":

1. thread1进入#1, 这时thread1的instance为null,thread1让出CPU资源给thread2.
2. thread2进入#1, 这时thread2的instance为null,thread2让出CPU资源给thread1.
3. thread1会依次执行#2,#3,#4,最终在thread1里面实例化了instance。thread1执行完毕让出CPU资源给thread2.
4. thread2接着#1跑下去,跑到#3的时候,由于#1里面拿到的instance还是null(并没有及时从thread1里面拿到最新的),所以thread2仍然会执行#3,#4.
5. 最后thread1和thread2都实例化了instance.

如果"private volatile static Singleton instance = null;":

1. thread1进入#1, 这时thread1的instance为null(java内存模型会从主内存里拷贝一份instance(null)到thread1),thread1让出CPU资源给thread2.
2. thread2进入#1, 这时thread2的instance为null(java内存模型会从主内存里拷贝一份instance(null)到thread2), thread2让出CPU资源给thread1.
3. thread1会依次执行#2,#3,#4, 最终在thread1里面实例化了instance(由于是volatile修饰的变量,会马上同步到主内存的变量去)。thread1执行完毕让出CPU资源给thread2.
4. thread2接着#1跑下去,跑到#3的时候,会又一次从主内存拷贝一份instance(!=null)回来,所以thread2就直接跑到了#5.
5. 最后thread2不会再重复实例化instance了.

由此可以看出,双重检查也是为了线程安全!!!

(2)防止重排序:

在单例模式中,Instance instance= new Instance();   这一句代码不是原子操作,它可以分成三步原子指令:

1.分配内存地址;

2.new一个Instance对象;

3.将内存地址赋值给instance;

CPU为了提高执行效率,这三步操作的顺序可以是123,也可以是132。如果是132顺序的话,当把内存地址赋给inst后,inst指向的内存地址上面还没有new出来单例对象,这时候如果就拿到instance的话,它其实就是空的,会报空指针异常。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值