设计模式之单例模式入门

136 阅读2分钟

1.饿汉式

public class DesignMode {
    //构造器私有
    private DesignMode(){

    }
    //饿汉式单例模式
    private static final DesignMode designMode=new DesignMode();

    public DesignMode getInstance (){
        return designMode;
    }
}

  饿汉式类内部的对象会在类的初始化过程中就被创建,即使后续可能根本没用到我们的designMode对象,也会被创建出来,这样的缺点是可能会浪费空间

2.懒汉式

public class DesignMode {
    //构造器私有
    private DesignMode(){

    }
    //懒汉式单例模式
    private static DesignMode designMode;

    public static DesignMode getInstance (){
        if(designMode==null){
            designMode=new DesignMode();
        }
        return designMode;
    }
}

  当第一次被要求获得对象时才会被初始化,避免了空间浪费的问题。但是在多线程状态下,可能会出现并发问题,下面介绍解决方法

2.1双重检测锁(DCL)懒汉式

public class DesignMode {
    //构造器私有
    private DesignMode(){

    }
    //懒汉式单例模式
    private static DesignMode designMode;

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

  两次检查是否为空(两次检查的理由是:第一次是在没有同步的情况下,如果检查出不为空,那就省事了,直接用designMode就行,否则就同步了之后再检查一次是否为空)。
  但是这个方法仍然不是完美的,由于new DesignMode这个过程不是原子性的,因此存在一种可能,即A线程尚未完成对象的初始化,但是designMode这个指针已经指向了一片地址空间(即不为null),与此同时B线程视图直接把designMode对象返回,这样就会出现问题。
  解决方法是声明designMode为volatile的。

public class DesignMode {
    //构造器私有
    private DesignMode(){

    }
    //懒汉式单例模式
    private static volatile DesignMode designMode;

    public static DesignMode getInstance (){
        if(designMode==null){
            synchronized (DesignMode.class){
                if (designMode==null){
                    designMode=new DesignMode();
                }
            }

        }
        return designMode;
    }
}

3.反射单例

  即使完成了上面的这些优化,懒汉式仍然存在一些缺陷。比如可以使用反射来躲过我们在getInstance中的检查,来直接调用私有的构造器方法。要解决这个问题可以使用枚举,java从底层源码的层面避免了枚举类型被反射破坏单一性的情况(无法用反射的newInstance方法来创建一个枚举类)。

public enum DesignMode {
    Instance;

    public static DesignMode getInstance(){
        return Instance;
    }
}