下面展示两种公认为最优的单例模式的写法
单例模式写法还是很多的,下面来介绍一下都优在哪
掌握这两种方法既可搞定单例模式.
懒汉式
public class Singleton {
// 私有化构造函数
private Singleton() {}
// 返回对象实例
public static Singleton getInstance() {
return SingletonHolder.instance;
}
private static class SingletonHolder{
// 直接创建对象
private static final Singleton instance = new Singleton();
}
}
通常来说,作为为刚接触java的人来说写的懒汉式并不是这样,而是直接在类中把新建的单例作为成员变量创建,因为被static修饰,所以在类加载的时候就会创建这个对象,而不是当我们需要时,再创建.这也是为什么到处都可以看到说懒汉式不如饿汉式的原因.但是创建一个静态内部类就不同了,静态内部类是Singleton的成员,单例是在内部类内部创建的,只有当你调用这个单例的时候才会创建.这个地方可能会有点费解,你就想象一个内部类中的单例不是一个成员变量,而是一个成员方法,你不去调用这个方法,会走这个方法吗.当然不会. 这种方法被公认为是最优内部类写法,推荐使用这种写法.
饿汉式
public class Singleton {
private volatile static Singleton instance; //声明成 volatile 保证编译器不进行优化
private Singleton (){}
public static Singleton getSingleton() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
饿汉式,只有在使用的时候才会创建.另一种常见的写法是在方法上加synchronized 关键字.但是这样会有一个问题,即使单例已经被初始化,每次调用getInstance方法都会进行同步,这样会消耗不必要的资源,这也是懒汉单例存在最大的问题,所以这种 写法不推荐,而且这种写法如果两个线程同时进入getInstance方法可能会创建两个对象.虽然这样说,但是我觉得不太可能.
再来说优化后的我们这种写法,可以看到getInstance方法中对instance进行了两次判空:第一层判断主要是为了避免不必要的同步,第二层的判断则是为了在null的情况下创建实例.