在一个系统中,要求一个类有且仅有一个对象,具体使用场景如下:
public class Singleton { private static Singleton instance = new Singleton(); private Singleton() { } public static Singleton getInstance(){ return instance; } } 复制代码
public class Singleton { private static Singleton instance; private Singleton() { } public static Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } } 复制代码
public class Singleton { private static Singleton instance; private Singleton() { } public static synchronized Singleton getInstance(){ if(instance == null){ instance = new Singleton(); } return instance; } } 复制代码
getInstance
方法时都需要同步,这会造成不必要的同步开销。 大部分时候我们是用不到同步的,所以,不建议用这种模式。
public class Singleton { private volatile static Singleton instance; private Singleton() { } public static Singleton getInstance(){ if(instance == null){ synchronized (Singleton.class) { if(instance == null) { instance = new Singleton(); } } } return instance; } } 复制代码
volatile
DCL
(Double Check Lock) 在高并发环境下也会有一定的缺陷, DCL
虽然在一定程度上解决了资源的消耗、多余的同步、线程安全问题等问题,但还是在某些情况会出现失效的问题,也就是 DCL
失效。这里建议用静态内部类单例模式来代替 DCL
。
public class Singleton { private Singleton() { } public static Singleton getInstance(){ return SingletonHolder.sInstance; } private static class SingletonHolder { private static final Singleton sInstance = new Singleton(); } } 复制代码
第一次加载 Singleton
类时并不会初始化 sInstance
。 只有在第一次调用 getInstance
方法时虚拟机才会加载 SingletonHolder
并初始化 sInstance。
public enum Singleton { INSTANCE; public void doSomeThing() { } } 复制代码
总结:到这里6种单例写法已介绍完,至于选择那种形势的单例模式,取决与你项目本身情况:是否复杂的高并发环境,或者是否需要控制单例对象的资源消耗。