# 单件模式

# 什么是单件模式

  • 单件模式:确保一个类只有一个实例,并提供一个全局访问点
  • 有些对象我们只需要一个实例,例如线程池,缓存,对话框,全局设置对象,设备的驱动程序,等等;
  • 我们并不通过设置 “全局变量” 来实现单件模式;
    • 因为如果把对象赋值给一个全局变量,那么我们就要在程序一开始就创建好对象;
    • 如果对象创建非常浪费资源(内存,时间)。那么这样就会很影响性能;
  • 通过单件模式,我们在需要时才创建对象;
  • 并且我们需要保证,这个实例是唯一的。不能被创建第二次;

# 经典的单件模式实现

  • 定义一个单例类;
  • 里面用一个和单例类同类型的私有静态属性,来储存单例的唯一实例;
  • 单例类的构造函数必须是私有的,这样外部就不可以调用构造函数去创建其他的实例了;
  • getInstance 是一个公开的静态方法:
    • 它里面会先判断实例是否已经被创建,如果没有就创建一个,并且返回实例给外部;
    • 如果已经创建了实例,就直接返回实例;
public class Singleton {
  private static Singleton uniqueInstance = null;

  private Singleton() {}

  // 只有 getInstance 是 public 的,
  // 用户通过它来获取实例
  public static Singleton getInstance() {
    if(uniqueInstance == null) {
      uniqueInstance = new Singleton();
    }

    return uniqueInstance;
  }
}

# 处理多线程的单件模式

  • 上面的单例实现方法,在多线程中可能会出现问题;
  • 多线程的话,对于当前实例的状态是不确定的;
  • 比如可能会产生两个对象开始发现都为空,于是在 JVM 中就新建了两个对象;

2020-2-19-22-35-17.png

# 通过 synchronized 关键字解决

  • 在新建对象的方法上加上 synchronized 关键字,可以保证不会有两个线程同时进入到这个方法中;
  • 但同步会降低性能,因为要进行判断这个方法的状态;
  • 一旦这个变量已经实例化了,每次访问还是同步的话,就是一种累赘;
  • 同步一个方法,会使程序运行效率下降 100 倍;
class Singleton {
    private static Singleton singleton;

    private Singleton() {
    }

    public static synchronized Singleton getInstance() {
        if (singleton == null) {
            singleton = new Singleton();
        }
        return singleton;
    }
}

# 直接实例化

  • 如果创建实例并不需要消耗太多资源;
  • 那么可以直接在定义类时,直接初始化实例;
  • JVM 会在加载这个类时,立马创建唯一的单件实例;
class SingletonFast {
    private static SingletonFast singleton = new SingletonFast();

    private SingletonFast() {
    }

    public static SingletonFast getInstance() {
        return singleton;
    }
}

# 双重检查加锁

  • 通过 “双重检查加锁”,我们首选检查是否实例已经创建了;
  • 如果没有创建,才进行同步;
  • 这样只有第一次会进行同步;
  • 可以大大提升性能;
class Singleton {
    //volatile关键词确保,当singleton变量被初始化成Singleton实例时,多个线程正确处理singleton变量
    private volatile static Singleton singleton;

    private Singleton() {
    }

    public static Singleton getInstance() {
        //如果不存在,就进入同步区块
        if (singleton == null) {
            //只有第一次才彻底执行这里的代码
            synchronized (Singleton.class) {
                if (singleton == null) {
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}
上次更新: 8/22/2020, 8:14:09 AM