单例模式

128 阅读2分钟

饿汉式

饿汉式:类加载的时候就把类实例化了。

饿汉式-静态成员变量

public class Singleton1 {

    public static Singleton1 instance = new Singleton1();

    public static Singleton1 getInstance() {
        return instance;
    }


    private Singleton1(){
    }
}

饿汉式-静态代码块

public class Singleton2 {

    public static Singleton2 instance;

    private Singleton2(){
    }

    /**
     * 静态代码块
     */
    static {
        instance = new Singleton2();
    }

    public static Singleton2 getInstance() {
        return instance;
    }
}

静态代码块在类加载的时候加载,静态代码块比构造先加载。

懒汉式

类不预先加载,在调用相应方法的时候才去加载。

懒汉式 - 单重检查,线程不安全

public class Singleton3 {
    private static Singtelon3 instance;
    //私有化构造方法
    private Singleton3{
    }
    
    public static Singleton3 getInstance() {
        if (instance == null){
            instance = new Singleton3();
          }
          return instance;
    }
}

懒汉式 - 方法级别加锁

public class Singleton4 {
    //valatile关键字能使的该属性在线程间共享,同时能静止指令重排序
    public static volatile Singleton4 instance;
    //私有化构造方法
    private Sing(){}
    
    public static synchronized Singleton4 getInstance() {
        if (instance == null) {
            instance = new Singleton4();
        }
        return instance;
    }

方法层面上加锁,它的效率很慢。

懒汉式 - 双重检查

public class Singleton5 {
    public static volatile Singleton4 instance;
    
    private Singleton5() {}
    
    public static Singleton5 getInstance() {
        if (instance == null) {
            //只有一个线程进入
            synchronized(Singleton5.class) {
                // 判断其他线程是否已经创建了实例
                if (instance == null) {
                    instance = new Singleton5();
                }
            }
        }
            return instance;
    }
}

第一层判断可能会有多个线程在未创建出实例时进入,加锁只让一个线程去创建,这时还有其他线程已经进入去获取锁,但是第二层检查,发现已经创建就不再创建,直接返回。

懒汉式 - 静态内部类方式

public class Singleton7 {
    
    private Singleton7() {}
    
    //静态内部类
    private static class SingletonHolder {
        private static final Singleton7 INSTANCE = new Singleton();
    }
    
    public static Singleton7 getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

枚举方式 - 也是饿汉式

public enum Singleton6 {
    //枚举使用了该类的默认构造,如果重写了构造,枚举使用的就是重写后的构造。
    
    //默认构造
    SINGLETON_6;
}

可能存在的问题

  1. 除枚举方式外,其他方式通过序列化和反序列化会破坏单例模式。