JAVA在多线程的环境下的单例模式双重校验锁究竟是怎么回事?

JAVA在多线程的环境下的单例模式双重校验锁究竟是怎么回事?

什么是单例模式?

单例模式:类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。

说简单点了就是不用new Class()的方式创建对象,直接用Class.getInstance()的方式去获取这个类唯一的对象。(此处Class为声明类名)
举个栗子

public class Singleton {  
  private volatile static Singleton instance;  /*类的属性必须为volatile+static
    volatile共享锁的性质可以保证类属性对所有线程可见
    static使Singleton类可以不通过对象去访问类属性*/
   private Singleton (){}  //构造方法必须为private
   public static Singleton getInstance() {  //必须有一个获取单例的方法比如getInstance()
   if (instance== null) {  //第一次校验
       synchronized (Singleton.class) {//当线程进入此步骤即对整个类信息加锁 
       if (instance== null) {  //第二次校验
           instance = new Singleton();  //两次交验都为空的话即创建实例
       }  
       }  
   }  
   return instance;  
   }  
}

单例模式的七个要求

1.成员变量volatile
2.成员变量static
3.构造函数私有
4.getInstance方法静态
5.getInstance方法第一层有校验
6.getInstance方法第二层有校验
7.在第一层校验后给类信息加锁synchronized

为什么要双重校验?

首先我们假设有两个线程A和B并且只有第一层校验,代码变成下面的这样:

public class Singleton {  
  private volatile static Singleton instance;  //类的属性必须为volatile static
   private Singleton (){}  //构造方法必须为private
   public static Singleton getInstance() {  //必须有一个获取单例的方法比如getInstance()
   if (instance== null) {  //第一次校验
       synchronized (Singleton.class) {//当线程进入此步骤即对整个类信息加锁 
     //第二层if删去了
           instance = new Singleton();  //两次交验都为空的话即创建实例
       
       }  
   }  
   return instance;  
   }  
}

这段代码有可能运行以下情况:
第一步:线程A获取CPU执行完第一次校验,但是此时到没有对整个类信息加锁这一步,线程A失去CPU资源,将A线程的当前运行状态保存。
第二步:线程B获取CPU执行完第一次校验,并且成功对类信息加锁,此时线程B持有锁,然后成功执行instance=new Singleton();创建Singleton实例,此时我们称这个引用为b1。线程B释放锁
第三步:线程A再次获取CPU,经过上下文切换,默认执行完第一次校验,然后对类信息加锁,线程A执行instance=new Singleton();,创建Singleton实例,此时我们称这个引用为a1。
从这一步开始就已经打破了单例模式的要求

====================华
接下来我们把第二重校验恢复:
第一步:线程A获取CPU执行完第一次校验,但是此时到没有对整个类信息加锁这一步,线程A失去CPU资源,将A线程的当前运行状态保存。
第二步:线程B获取CPU执行完第一次校验,并且成功对类信息加锁,此时线程B持有锁进行第一重校验成功,然后成功执行instance=new Singleton();创建Singleton实例,此时我们称这个引用为b1。线程B释放锁
第三步:线程A再次获取CPU,经过上下文切换,默认执行完第一次校验,然后对类信息加锁,第二重校验失败,线程A释放锁。

此处我们假设有第三个线程C参与竞争:
第三步:线程C获取CPU,执行第一次校验失败,线程C释放锁。

结论可得,在多线程环境下,单例模式进行双重校验锁就是为了提高线程安全性,防止多个线程创建额外的类实例。

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值