单例模式是一种对象建立模式,用于产生一个类的具体事例。使用单例模式能够确保整个系统中单例类只产生一个实例。有下面两大好处:java
- 对于频繁建立的对象,节省初第一次实例化以后的建立时间。
- 因为new操做的减小,会下降系统内存的使用频率。减轻GC压力,从而缩短GC停顿时间
建立方式:安全
- 单例做为类的私有private属性
- 单例类拥有私有private构造函数
- 提供获取实例的public方法
单例模式的角色:性能优化
角色 | 做用 |
---|---|
单例类 | 提供单例的工厂,返回类的单例实例 |
使用者 | 获取并使用单例类 |
类基本结构:多线程
public class HungerSingleton { //1.饿汉式 //私有构造器 private HungerSingleton() { System.out.println("create HungerSingleton"); } //私有单例属性 private static HungerSingleton instance = new HungerSingleton(); //获取单例的方法 public static HungerSingleton getInstance() { return instance; } }
注意:jvm
public class Singleton { //2.1简单懒汉式(线程不安全) //私有构造器 private Singleton() { System.out.println("create Singleton"); } //私有单例属性[初始化为null] private static Singleton instance = null; //获取单例的方法 public static Singleton getInstance() { if(instance == null) { //此处instance实例化 //首次调用单例时会进入 达成延时加载 instance = new Singleton(); } return instance; } }
public class Singleton { //2.2简单懒汉式(线程安全) //私有构造器 private Singleton() { System.out.println("create Singleton"); } //私有单例属性[初始化为null] private static Singleton instance = null; //获取单例的方法 将此方法使用synchronized关键字同步 public static synchronized Singleton getInstance() { if(instance == null) { //此处instance实例化 //首次调用单例时会进入 达成延时加载 instance = new Singleton(); } return instance; } }
面临的问题:函数
简单懒汉式(线程安全)中,对getInstance()方法加锁,致使多线程中性能较差,那么是否能够 减少锁的范围,使不用每次调用geInstance()方法时候都会去竞争锁?DCL(Double Check Locking)双重检测 就是这样一种实现方式。性能
public class DCLLazySingleton { //3.DCL //私有构造器 private DCLLazySingleton() { System.out.println("create DCLLazySingleton"); } //私有单例属性[初始化为null] volatile 保证内存可见性 防止指令重排 private static volatile DCLLazySingleton instance = null;//step1 //获取单例的方法 public static DCLLazySingleton getInstance() { //这里判null 是为了在instance有值时,不进入加锁的代码块,提升代码性能。 if(instance == null) { //缩小锁范围 因为是静态方法方法调用的时候不依赖于实例化的对象 加锁只能使用类 synchronized (DCLLazySingleton.class) { //这里判null 是为了配合volatile解决多线程安全问题 if(instance == null) { instance = new DCLLazySingleton(); } } } return instance; } }
注意:优化
传统DCL(step1处并未使用 volatile 或使用了但在JDK1.8以前)面临的问题:spa
解决方式:.net
参考:
public class StaticSingleton { //私有构造器 private StaticSingleton() { System.out.println("create StaticSingleton!"); } //获取单例的方法 public static StaticSingleton getInstance() { return SingletonHolder.instance; } //静态内部类 持有单例 做为静态属性。 //因为只有在访问属性时才会加载静态类初始化instance。因此实现了懒加载。且因为JVM保证了类的加载为线程安全,因此为线程安全的。 private static class SingletonHolder { //私有单例属性 private static StaticSingleton instance = new StaticSingleton(); } }
注意:
public enum EnumSingleton { INSTANCE(); EnumSingleton() { System.out.println("create EnumSingleton"); } }
上述的单例实现方式仍是会面临一些特殊状况不能保证惟一实例:
private Object readResolve () { //返回当前对象 return instance; }
因为上述两状况比较特殊,因此没有特别关注。
《Java程序性能优化》 -葛一鸣 等编著