在应用程序中,常常会用到单例模式,即这个类只能存在一个对象实例。
那么为何须要这种模式,咱们在一个程序应用中,只须要建立一次性的对象实例以节省内存资源,避免重复建立的开销,以便后面使用能够更快的访问。java
单例做为全部设计模式中最简单的设计模式之一,其建立是很是简单的。设计模式
#code 饿汉式单例-不推荐 public final class HungrySingleton { private byte[] data = new byte[1024]; private static HungrySingleton instance = new HungrySingleton(); private HungrySingleton() { } public static HungrySingleton getInstance() { return instance; } }
以上就是一个典型的饿汉式单例模式,在咱们调用HungrySingleton. getInstance()方法时,不单单获取了一个已经建立的对象,而且获取了已经初始化了的1k的类变量数据。
即使在多线程环境下,instance也不会被建立两次,由于在类初始化的时候被收集进
可是这个有一个缺陷,instance在被类加载以后,很长一段时间都会被常驻在堆内存,若是这个一个轻量级的类,那却是无所谓,但若是这个类比较重,那么这种建立方式就不太稳当。
#code 懒汉式单例-不推荐 public final class LazySingleton { private static LazySingleton instance = null; private LazySingleton() { } public static synchronized LazySingleton getInstance() { if (null == instance) { instance = new LazySingleton(); } return instance; } }
上面这一段代码其实就是懒汉式单例,咱们在真正调用getInstance()方法的时候才去建立这个实例,这个类所需的资源到这个时候才会被开辟。咱们同时也使用synchronized来保证多线程环境下只有一份实例。
看起来很美妙,但惋惜的是,这个方式也一样不被推荐。缘由也很简单,由于咱们在使用getInstance()的时候是同步的,意味着每一个调用该方法的线程都必须阻塞等待其余线程调用完成,这一点就很耗费性能。多线程
#code 双重检查式单例-不推荐 public final class DCSingleton { private static volatile DCSingleton instance; private DCSingleton() { } public static DCSingleton getInstance(){ if (null == instance){ synchronized (DCSingleton.class){ if (null == instance){ instance = new DCSingleton(); } } } return instance; } }
在我很长的一段时间内以来,在建立单例实例的时候都喜欢使用这种方式。它既保证了线程安全,也保证了延迟加载,同时相比懒汉式单例的耗费性能,它使用的双重检查的技巧很大程度上缓解了性能浪费,并且volatile修饰的instance也不会被指令重排困扰。看上去很完美,从必定程度上来讲的确是这样。
直到我看了doug lea与人合著的那本并发实践书籍,原文是这样的:“DCL这种使用方法已经被普遍的废弃了——促使该模式出现的驱动力不复存在,于是它不是一种高效的优化措施。延迟初始化占位类模式能带来一样的优点,而且更容易理解。”这里的驱动力是指,在新的版本下,无竞争同步的执行速度变快了(之前很慢),JVM的启动速度也变快了(之前很慢)。并发
#code Holder式单例-推荐max public final class HolderSingleton { private HolderSingleton() { } private static class Holder { private static HolderSingleton instance = new HolderSingleton(); } public static HolderSingleton getInstance() { return Holder.instance; } }
从线程安全、高性能、懒加载来看,这个应该是目前最好的单例设计之一,也是使用最为普遍的一个。性能
#code Holder式单例-酌情使用 public enum EnumSingleton { INSTANCE; EnumSingleton() { System.out.println("complete init..."); } public static EnumSingleton getInstance() { System.out.println("getInstance..."); return INSTANCE; } public static void doneTask() { System.out.println("doneTask..."); } }
在《Effective Java》那本书中,这个枚举方式实现单例的方式就被极为推荐。枚举方式不容许被继承,一样也只是被实例化一次,可是不可以懒加载。因此读者能够酌情使用。优化