单例模式

196 阅读3分钟

1. 懒汉式

静态变量

public class StaticVariable {
    /**
     * 1.构造器私有化 外部不能new
     */
    private StaticVariable(){}

    /**
     * 2.本类内部创建对象实例 StaticVariable
     */
    private final static StaticVariable singleton = new StaticVariable();

    /**
     * 提供一个公有的静态方法 返回对象实例
     * @return
     */
    public static StaticVariable getInstance(){
        return singleton;
    }
}

静态代码块

public class StaticCodeBlock {

    /**
     * 1.构造器私有化 外部不能new
     */
    private StaticCodeBlock(){}

    private static StaticCodeBlock singleton;

    /**
     * 2.在静态代码块中创建单例对象 从这里可以看出静态变量的执行顺序比静态代码块先执行
     */
    static {
        singleton = new StaticCodeBlock();
    }

    /**
     * 3.提供一个公有的静态方法 返回对象实例
     * @return
     */
    public static StaticCodeBlock getInstance(){
        return singleton;
    }
}

2. 饿汉式

静态方法

//线程不安全 开发不能使用 会违反单例模式的初衷
public class StaticMethod {

    private StaticMethod(){}

    private static StaticMethod singletonThree;

    public static StaticMethod getInstance(){
        if (singletonThree == null){
            singletonThree = new StaticMethod();
        }
        return singletonThree;
    }
}

同步方法

//(线程安全 同步方法 效率太低 不建议使用) 但是JDK1.8 synchronized锁升级 性能并不差
public class SynchronizationMethod {

    private SynchronizationMethod(){}

    private static SynchronizationMethod instance;

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

静态内部类加载

//SingletonSeven加载时 SingletonInstance不会加载 加载的时候只会加载一次 能确保懒加载 又能实现单例模式
public class StaticInnerClass {

    private StaticInnerClass(){}

    private static class SingletonInstance{
        private static final StaticInnerClass instance = new StaticInnerClass();
    }

    public static StaticInnerClass getInstance(){
        return SingletonInstance.instance;
    }
}

同步代码快

//线程安全 同步代码快 不能起到线程同步的作用 会违反单例模式的初衷 实际开发中不能使用这种写法)原因是Jvm会指令重排 对象的初始化过程中 初始化顺序错乱
public class FastSynchronizationCode {

    private FastSynchronizationCode(){}

    private static FastSynchronizationCode instance;

    private static FastSynchronizationCode getInstance(){
        if (instance == null){
            synchronized (FastSynchronizationCode.class){
                instance = new FastSynchronizationCode();
            }
        }
        return instance;
    }
}

双重检查

public class DCL {

    private DCL(){}

    /**
     * volatile 可以让修改的内容立即更新到内存(可见性 有序性---防止指令重排) 可以理解为轻量级的 synchronized
     */
    private static volatile DCL instance;

    private static DCL getInstance(){
        if (instance == null){
            synchronized (DCL.class){
                if (instance == null){
                    instance = new DCL();
                }
            }
        }
        return instance;
    }

}

3. 枚举

//推荐使用 不仅能避免多线程同步问题 还能防止反序列化重新创建新的对象
public enum Enumerate {
    INSTANCE;
}

class Test {

    public static void main(String[] args) {
        System.out.println(Enumerate.INSTANCE == Enumerate.INSTANCE);
    }

}

4.应用

我们JDK中,java.lang.Runtime就是经典的单例模式(饿汉式) 源码简单自行查看

单例模式注意事项和细节说明:

  • 单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
  • 当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new
  • 单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)