单例模式中的饿汉模式和懒汉模式【一看就懂】

以Java为例:

饿汉:

public final class VirtualCore {
private static VirtualCore gCore = new VirtualCore();

    private VirtualCore() {

    }
    public static VirtualCore get() {
        return gCore;
    }
}

懒汉:

public final class VirtualCore {
private static VirtualCore gCore = null;

    private VirtualCore() {

    }
    public static synchronized VirtualCore get() {
        if(gCore == null){
            gCore = new VirtualCore();
        }
        return gCore;
    }
}

先来看单例模式原理及要求,保证这个类在内存中只有一个对象,那么就不能随便给别人new,所以必须把构造函数改为private,然后整一个公共静态方法供外部统一获取实例。

 

再来看饿汉以及懒汉定义(原理)以及区别:

饿汉:一开始就吧吃的找好(对象new出来),随时可以吃

懒汉:懒得动,饿了(有需要)再去找吃的(new 对象)

 

两者区别在于,饿汉模式拿空间换时间,一开始就把对象生成,在内存中占着,懒汉则是按需生成。注意的是,多线程访问的时候,

懒汉可能会因为不同步创建多个对象,所以聪明的人们在获取单例的方法加上 synchronized字段~

public final class VirtualCore {
private static VirtualCore gCore = null;

    private VirtualCore() {

    }
    public static synchronized VirtualCore get() {
        if(gCore == null){
            synchronized(VirtualCore.class){
                if(gCore == null){
                    gCore = new VirtualCore();
                }
            }
        }
        return gCore;
    }
}            

这就是 DoubleCheckLock(DCL)双检锁,DCL虽然在一定程度上解决了资源消耗、多余的同步、线程安全等问题,但是,

它还是在某些情况下会出现失效的问题。这个问题被称为双重检查锁定(DCL)失效,在《Java并发编程实践》一书的最后

谈到了这个问题,并指出这种“优化”是丑陋的,不赞成使用。而建议使用如下的代码替代:

1 public class VirtualCore {
2     private VirtualCore(){}
3     public static VirtualCore getInstance(){
4         return VirtualCoreHolder.gCore;
5     }
6     private static class VirtualCoreHolder{
7         private static final VirtualCore gCore = new VirtualCore();
8     }
9 }

当第一次加载VirtualCore类时并不会初始化gCore,只有在第一次调用VirtualCore的getInstance方法时才会导致gCore被初始化。因此第一次调用getInstance方法会导致

虚拟机加载VirtualCoreHolder类,这种方式不仅能够确保线程安全,也能够保证单例的实例化,所以这是推荐使用的单例模式实现方式!

posted on 2019-12-27 10:51  益达的博客  阅读(1070)  评论(0编辑  收藏  举报

导航