设计模式-懒汉式

设计模式-懒汉式


代码

public class LazySingleton {
    //私有构造方法
    private static LazySingleton instance;

    private LazySingleton(){};

    public static LazySingleton getInstance(){
        if (instance ==null){
            instance = new LazySingleton();
        }
        return instance;
    }    
}

分析

优点:节省了内存(相对于饿汉式),只有在调用方法的时候才会实例化
缺点:线程不安全:当多线程的时候,可能会出现线程不安全的情况。当两个线程都进入if 条件的时候,可能会生成两个实例( 如何调试多线程及为何线程不安全)。

进阶

如何保证线程安全,既然这样的单例模式,在多线程情况下没有办法保证他是线程安全的,那么如何解决–synchronized这里我们使用synchronized来保证它在多线程的情况下是线程安全的,代码如下:

	public class LazySingleton {
    //私有构造方法
    private static LazySingleton instance;
    private LazySingleton() {
    };
    //使用synchronized 关键字来保证线程安全
    public synchronized static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

这样的改造下,确实可以保证线程是安全的,但是会衍生新的问题:synchronized 在使用时会控制所有的线程,保证只会有一个线程访问到这个方法。假设现在有N多的线程,都要来调用这个方法。那么当有一个线程进入方法后,其余所有的线程都是等待的状态,会造成线程的阻塞。那有没有更好的办法呢?既然现在都阻塞在了方法外,那就让方法在进来之后再做判断:

	public class LazySingleton {
    //私有构造方法
    private static LazySingleton instance;
    private LazySingleton() {
    };

    public synchronized static LazySingleton getInstance() {
        if (instance == null) {
            //使用synchronized 关键字来保证线程安全
           	synchronized (DoubleCheckLazySingleton.class){
       	        instance = new LazySingleton();
        	 }   
        }
        return instance;
    }
}

这样就可以保证线程不会都阻塞在方法外,只有在判断是否生成实例的时候才会进行阻塞。这样可以有效的“过滤”掉部分问题。。但是又会产生新的问题:线程又双叒叕不安全了。。。那如果再保证线程安全呢?这时候就要进入一个大家都熟悉的地方了:双重校验

public class DoubleCheckLazySingleton {
//私有构造方法
private static DoubleCheckLazySingleton instance;
private DoubleCheckLazySingleton(){};
public  static DoubleCheckLazySingleton getInstance(){
    //检查是否要阻塞
        if (instance == null){
            synchronized (DoubleCheckLazySingleton.class){
                //检查是否要重新创建实例
                if (instance == null){
                    instance = new DoubleCheckLazySingleton();
                }
            }
        }
        return instance;
	}
}

可以看到这里检测了两次instance==null,但是两次检测的作用不一样。一次是判断是否需要阻塞。如果已经生成了实例,那么所有的进程就没有必要阻塞,第二次判断,检查是否需要重新创建实例。

总结

懒汉式相对于饿汉式来说,虽然线程不安全,但是在后续做了某些操作后(双重校验),可以保证线程安全,不过代码量上明显多于饿汉式。
最后,还遗留了一个问题:指令重排序。这里就先不做讨论了。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值