设计模式之单例模式

单例模式的几种实现

所谓单例,就是整个程序有且仅有一个实例。该类负责创建自己的对象,同时确保只有一个对象被创建。在Java,一般常用在工具类的实现。

特点

  • 类构造器私有
  • 持有自己类型的属性
  • 对外提供获取实例的静态方法

实现方式:

饿汉模式

线程安全,比较常用,但是会浪费空间,因为一开始就初始化

public class Singleton{
    private Singleton(){}
    
    private final static Singleton instance = new Singleton();
    
    public static Singleton getInstance(){
        return instance;
    }
}

懒汉模式

线程不安全,延迟初始化,容易被反射攻击

public class Singleton{
    private Singleton(){}
    
    private static Singleton instance = null;
    
    public static Singleton getInstance(){
        if (instance == null) {
            instance = new LazyMan();
        }
        return instance;
    }
}

懒汉模式:双重校验锁

public class Singleton{
    private Singleton(){}
    
    // 双重锁必须加 volatile
    private volatile static Singleton instance = null;
    
    public static Singleton getInstance(){
        if (instance == null) {
            synchronized (Singleton.class){
                if(instance == null){
                    instance = new Singleton();	// 不是原子操作
                  	/**
                  	 * 1. 分配内存
                  	 * 2. 执行构造
                  	 * 3. 对象指向内存
                  	 * 可能发生重排
                  	 */
                }
            }
        }
        return instance;
    }
}

双重检查模式,进行了两次的判断,第一次是为了避免不要的实例,第二次是为了进行同步,避免多线程问题。由于singleton=new Singleton()对象的创建在JVM中可能会进行重排序,在多线程访问下存在风险,使用volatile修饰signleton实例变量有效,解决该问题。

懒汉模式:静态内部类

public class Singleton{
    private Singleton(){}
    
    private static class Inner{
        private static final Singleton instance = new Singleton();
    }
    
    public static Singleton getInstance(){
        return Inner.instance
    }
}

第一次调用getInstance方法时,虚拟机才加载 Inner 并初始化instance。


通过反射破坏:

Singleton instance  = Singleton.getInstance();

Constructor<Singleton> declaredConstructor = Singleton.class.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Singleton instance2 = declaredConstructor.newInstance();

System.out.println(instance == instance2); //false

懒汉模式:枚举

枚举本身是一个类

// 枚举方式 极为推荐的方式
enum Singleton {
    INSTANCE; //定义一个枚举的元素,就代表一个实例
    //一个enum的构造方法限制是private的

    public static Singleton getInstance() {
        return INSTANCE;
    }
}

使用:

Singleton instance = Singleton.INSTANCE;
Singleton instance = Singleton.getInstance();
posted @ 2020-08-29 20:29  小小小南瓜  阅读(119)  评论(0编辑  收藏  举报