Java双重校验锁实现单例模式

为什么要用双重校验锁实现单例模式?

单例实现有饿汉模式与懒汉模式,懒汉模式能够延迟加载,使用较多,但是懒汉模式在多线程下会出现问题,即有可能会产生多个实例。

下面是懒汉模式实现的单例模式的代码
public class SingleTon{
	//静态实例变量
	private static SingleTone instance;
	//无参构造函数
	private SingleTon(){}
	//获取单例的公共方法
	public static synchronized SingleTon getInstance(){
		if(instance == null){
			instance = new SingleTon();
		}
		return instance;
	}
}
下面是双重校验锁实现的额单例模式,极度保证线程安全
public class SingleTon{
	//静态实例变量
	private volatile static SingleTone instance;
	//无参构造函数
	private SingleTon(){}
	//获取单例的公共方法
	public static SingleTon getInstance(){
	    //先判断对象是否实例化过,如果没有实例化才进入加锁阶段
		if(instance == null){//第一重校验
			synchronized(SingleTon.class){
				if(instance == null){//第二重校验
					instance = new SingleTon();
				}
			}
		}
		return instance;
	}
}

以下引用一位博主的解释,原文链接https://blog.csdn.net/weixin_39309402/article/details/106421795

  • 第一次判断是否为null:
    第一次判断是在Synchronized同步代码块外,理由是单例模式只会创建一个实例,并通过getInstance方法返回singleton对象,所以如果已经创建了singleton对象,就不用进入同步代码块,不用竞争锁,直接返回前面创建的实例即可,这样大大提升效率。

  • 第二次判断singleton是否为null:
    第二次判断原因是为了保证同步,假若线程A通过了第一次判断,进入了同步代码块,但是还未执行,线程B就进来了(线程B获得CPU时间片),线程B也通过了第一次判断(线程A并未创建实例,所以B通过了第一次判断),准备进入同步代码块,假若这个时候不判断,就会存在这种情况:线程B创建了实例,此时恰好A也获得执行时间片,如果不加以判断,那么线程A也会创建一个实例,就会造成多实例的情况。

  • 所以,为了满足单例模式的要求,双重校验是必不可少的。

补充

实现线程且延迟加载还有另外一种实现方式
静态内部类实现单例模式
代码如下

public class SingleTon{
	//静态内部类
	private static class SingleTonHolder{
		//静态常量
		private static final SingleTon INSTANCE = new SingleTon();
	}
	//无参构造方法
	private SingleTon(){}
	//获取实例方法
	public static final SingleTon getInstance(){
		return SingleTonHolder.INSTANCE;
	}	
}

线程安全且延迟加载

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值