单例模式
1 package com.study; 2 3 import java.io.ObjectStreamException; 4 import java.io.Serializable; 5 import java.util.Objects; 6 7 /** 8 * 单例模式 9 * 1、类的创建模式,创建对象的最优方式,例如spring中管理的bean大部分为单例。 10 * 2、单例要素: 11 * 全局唯一的对象实例 12 * 单例类自己创建唯一的实例(禁止客户端调用创建) 13 * 单例类必须对外暴露(提供)获取对象实例的方法 14 * 导致单一实例失败问题: 15 * 1、调用反射,进行实例化 16 * 2、反序列化导致实例不一致 17 * 3、线程安全 18 */ 19 20 public class Singleton { 21 public static void main(String[] args) { 22 SingletonEnum instance = SingletonEnum.SINGLETON; 23 instance.doSomething(); 24 } 25 } 26 27 /** 28 * 饿汉 单例模式 29 * 即类加载就创建对象(并非调用getInstance时候加载,可能调用其他静态方法导致类加载),由类加载机制提供线程安全保障 30 * 优点:简单安全高效 31 * 缺点:不确定对象是否需要使用 32 */ 33 class SingletonNormal implements Serializable { 34 private static SingletonNormal singleton = new SingletonNormal(); 35 36 /** 37 * 1、将构造函数设置为私有的避免被new对象,破坏单一实例 38 */ 39 private SingletonNormal() { 40 //避免通过反射调用创建对象 41 if (!Objects.isNull(singleton)) { 42 throw new RuntimeException("实例已存在"); 43 } 44 } 45 46 /** 47 * 反序列化时候直接返回singleton实例,不需要重新实例化一个对象实例,避免反序列化造成多个实例 48 * 49 * @return 50 * @throws ObjectStreamException 51 */ 52 private Object readResolve() throws ObjectStreamException { 53 return singleton; 54 } 55 56 57 /** 58 * 返回实例 59 * 60 * @return 61 */ 62 public static SingletonNormal getInstance() { 63 return singleton; 64 } 65 66 /** 67 * 如果通过SingletonNormal.test()导致类加载,实例化对象,此时的instance并非真正需要,导致浪费内存 68 */ 69 public static void test() { 70 //do ... 71 } 72 } 73 74 /** 75 * 懒汉 单例模式 76 * 用于弥补实例消耗资源,将实例延迟到需要使用的时候创建的方案 77 * 优点:仅在通过调用SingletonLazy.getInstance()时候才会创建对象 78 * 缺点:因为同步方法,导致效率下降 79 */ 80 class SingletonLazy { 81 private static SingletonLazy singleton; 82 83 private SingletonLazy() { 84 //避免通过反射调用创建对象 85 if (!Objects.isNull(singleton)) { 86 throw new RuntimeException("实例已存在"); 87 } 88 } 89 90 /** 91 * 同步方法避免并发情况下创建多个实例 92 * 93 * @return 94 */ 95 public static synchronized SingletonLazy getInstance() { 96 if (Objects.isNull(singleton)) { 97 singleton = new SingletonLazy(); 98 } 99 return singleton; 100 } 101 } 102 103 /** 104 * 双重校验锁,主要用于弥补高并发下懒汉式的效率低下的方案 (不建议使用) 105 * 优点:提升效率 106 * 缺点:实现复杂,由于编译器优化等原因可能导致失败 107 */ 108 class SingletonDCL { 109 private static volatile SingletonDCL singleton = null;//volatile用于解决可见性问题 110 111 private SingletonDCL() { 112 //避免通过反射调用创建对象 113 if (!Objects.isNull(singleton)) { 114 throw new RuntimeException("实例已存在"); 115 } 116 } 117 118 /** 119 * 锁住类对象 120 * 121 * @return 122 */ 123 public static SingletonDCL getInstance() { 124 if (Objects.isNull(singleton)) { 125 SingletonDCL instance; 126 synchronized (SingletonDCL.class) { 127 instance = singleton; 128 if (Objects.isNull(instance)) { 129 synchronized (SingletonDCL.class) { 130 instance = new SingletonDCL(); 131 } 132 } 133 } 134 singleton = instance; 135 } 136 return singleton; 137 } 138 } 139 140 /** 141 * 内部类单例模式 142 * 通过定义内部类,然后由外表调用内部类的时候加载,由类加载保障安全 143 * 优点:高效、延迟加载 144 */ 145 class SingletonInner { 146 private static SingletonInner singleton; 147 148 private SingletonInner() { 149 //避免通过反射调用创建对象 150 if (!Objects.isNull(singleton)) { 151 throw new RuntimeException("实例已存在"); 152 } 153 } 154 155 /** 156 * 执行Singleton.INSTANCE时才会对内部类进行加载 157 */ 158 private static class Singleton { 159 private static final SingletonInner INSTANCE = new SingletonInner(); 160 } 161 162 public static SingletonInner getInstance() { 163 return Singleton.INSTANCE; 164 } 165 } 166 167 /** 168 * 枚举式单例(推荐使用) 169 * 由JVM保障安全/反序列化/反射等问题 170 * 优点:简单、高效、安全 171 * <p> 172 * SingletonEnum instance = SingletonEnum.SINGLETON; 173 */ 174 enum SingletonEnum { 175 SINGLETON; 176 177 public void doSomething() { 178 System.out.println("这是最佳的单例实现模式...."); 179 } 180 }
冰冻三尺非一日之寒!