单例模式的一些思考

单例模式的一些问题思考

public class A {
    private volatile static   A a;
    private A(){

    }

    public static A getInstance(){
      if(a ==null){
          synchronized (A.class){
              if(a==null){
                  a = new A();
              }
          }
      }
      return a;
    }

}

1.为什么synchronized 不加在方法上?

答案:细化锁,有可能获取实例的时候会在这上面写一些业务代码,这些业务代码不需要加锁,因此尽量少的锁定同步范围。

2 为什么要两次判断a == null

1.1 第一次判断为空,是为了提高效率,如果a不为空就直接返回对象,不用进行锁的竞争,提高了效率。
1.2 第二次判断为空,假如A线程和B线程同时进入了 A == null 这个if条件里面,然后A线程获得了A.class的锁,完成了初始化,这时候A释放锁,因为A已经执行完同步代码块了,释放锁,然后B开始执行了,如果没有里面的A==null判断,也去执行一次new A(),这时候就有两个对象了,就不是单例模式了。因此需要两次为空判断。

3.为什么要加volatile 变量

不加volatile变量,要理解这个问题需要知道,new Object,这个操作分为三个指令,1 分配内存空间,2. 初始化类的属性等
3. 建立类的属性引用, 如果A线程在进行new A()这个操作的同时,发生了指令重排序,意思就是1–>2–>3的这个操作变成了3 --> 2–>1,B线程这时候进来了,进入if (A == null)的判断,因为你3先执行了,这时候A==null是false,就直接去拿到A这个对象了,但是这个对象有个问题,就是没有完全的完成类的初始化,如果你B线程取A对象的值的时候,有可能取到为空的属性值。这时候,单例模式就有问题了。因此要加上volatile变量,禁止指令重排序,从而禁止你提前取对象,总结就是一句话,加这个属性的含义是禁止你拿到半成品对象,导致业务异常。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值