设计模式 之 单例- 2019-10-10 20:40:40- 设计模式: java,编程,设计模式,单例


概念
保证一个类的实例全局只有一个,并提供一个全局访问点。
特性
构造私有化
实现方式 8种

饿汉式

优点:不会产生线程问题,保证唯一单例
缺点;如果不使用时就初始化,会导致无用对象占用系统资源

  1. public class HungrySingleton {
  2. private static final HungrySingleton hungrySingleton = new HungrySingleton();
  3. /**
  4. * 构造私有化
  5. */
  6. private HungrySingleton() {
  7. }
  8. public static HungrySingleton getInstance() {
  9. return hungrySingleton;
  10. }
  11. }
  12. public class HungrySingletonThread implements Runnable {
  13. @Override
  14. public void run() {
  15. HungrySingleton instance = HungrySingleton.getInstance();
  16. System.out.println(instance);
  17. }
  18. }

懒汉式(线程安全/不安全)

线程不安全

* 优点:节省资源
* 缺点:有线程安全问题

  1. public class LazySingleton {
  2. private static LazySingleton lazySingleton = null;
  3. private LazySingleton() {
  4. }
  5. public static LazySingleton getInstance() {
  6. if (null == lazySingleton) {
  7. lazySingleton = new LazySingleton();
  8. }
  9. return lazySingleton;
  10. }
  11. }
  12. public class LazySingletonTread implements Runnable {
  13. @Override
  14. public void run() {
  15. LazySingleton laySingleton = LazySingleton.getInstance();
  16. System.out.println(laySingleton);
  17. }
  18. }

线程安全

* 优点:节省内存资源 无线程问题
* 缺点:性能下降 资源占用时间过长 ,会锁住整个类

  1. public class LazySyncSingleton {
  2. private static LazySyncSingleton lazySingleton = null;
  3. private LazySyncSingleton() {
  4. }
  5. public static synchronized LazySyncSingleton getInstance() {
  6. if (null == lazySingleton) {
  7. lazySingleton = new LazySyncSingleton();
  8. }
  9. return lazySingleton;
  10. }
  11. }
  12. public class LazySyncSingletonTread implements Runnable {
  13. @Override
  14. public void run() {
  15. LazySyncSingleton laySingleton = LazySyncSingleton.getInstance();
  16. System.out.println(laySingleton);
  17. }
  18. }

双重锁校验

  1. public class LazyDoubleCheckSyncSingleton {
  2. private static LazyDoubleCheckSyncSingleton lazySingleton = null;
  3. private LazyDoubleCheckSyncSingleton() {
  4. }
  5. public static LazyDoubleCheckSyncSingleton getInstance() {
  6. //一层校验:为了提高性能。如果将synchronized锁在方法上或是判断条件上,当有一个线程获取到锁的时候,
  7. // 其他线程就会处于等待状态,进入不了内部逻辑。
  8. if (null == lazySingleton) {
  9. synchronized (LazyDoubleCheckSyncSingleton.class) {
  10. //第二层校验 防止两个线程同时满足了第一层校验,再做一次校验,防止多次创建
  11. if (null == lazySingleton) {
  12. lazySingleton = new LazyDoubleCheckSyncSingleton();
  13. }
  14. }
  15. }
  16. return lazySingleton;
  17. }
  18. }
  19. public class LazyDoubleCheckSyncSingletonTread implements Runnable {
  20. @Override
  21. public void run() {
  22. LazyDoubleCheckSyncSingleton laySingleton = LazyDoubleCheckSyncSingleton.getInstance();
  23. System.out.println(laySingleton);
  24. }
  25. }

静态内部类

* 优点:性能最优。不需要使用线程,利用JVM加载静态内部类的机制保证多线程安全
* 懒汉式单例
* 缺点:
* 需要注意反射破坏单例的问题 解决:在构造中直接抛异常
* 需要注意序列化出现的问题 : 添加readResolve方法

  1. public class InnerSingleton implements Serializable, Cloneable {
  2. // private static Boolean open = true;
  3. private InnerSingleton() {
  4. // TODO: 设置开关这种方式不行 因为私有属性也可以被反射重新赋值
  5. // if (open) {
  6. // synchronized (InnerSingleton.class) {
  7. // if (open) {
  8. // open = false;
  9. // }
  10. // }
  11. // } else {
  12. // throw new RuntimeException("不可实例化");
  13. // }
  14. //被实例化后 类就被加载到内存中,不会被重复加载
  15. if (null != InnerSingletonHandle.inner) {
  16. throw new RuntimeException("不可实例化");
  17. }
  18. }
  19. public static InnerSingleton getInstance() {
  20. return InnerSingletonHandle.inner;
  21. }
  22. private static class InnerSingletonHandle {
  23. private static final InnerSingleton inner = new InnerSingleton();
  24. }
  25. /**
  26. * 解决反射问题
  27. *
  28. * @return
  29. */
  30. public Object readResolve() {
  31. return InnerSingletonHandle.inner;
  32. }
  33. /**
  34. * 允许复制实例
  35. * @return
  36. * @throws CloneNotSupportedException
  37. */
  38. @Override
  39. protected Object clone() throws CloneNotSupportedException {
  40. return InnerSingletonHandle.inner;
  41. }
  42. }
  43. public class InnerSingletonTread implements Runnable {
  44. @Override
  45. public void run() {
  46. InnerSingleton laySingleton = InnerSingleton.getInstance();
  47. System.out.println(laySingleton);
  48. }
  49. }

注册式单例:枚举

  1. public enum RegisterSingleton {
  2. SINGLETON;
  3. private Object object;
  4. public void setObject(Object object) {
  5. this.object = object;
  6. }
  7. public Object getObject() {
  8. return object;
  9. }
  10. public static RegisterSingleton getInstance() {
  11. return SINGLETON;
  12. }
  13. }
  14. public class RegisterSingletonThread implements Runnable {
  15. @Override
  16. public void run() {
  17. RegisterSingleton singleton = RegisterSingleton.SINGLETON;
  18. System.out.println(singleton);
  19. }
  20. }
  21. 容器式单例
  22. public class ContainerSingleton {
  23. private ContainerSingleton() {
  24. }
  25. private static Map<String, Object> container = new HashMap<>();
  26. public static Object getBean(String className) {
  27. try {
  28. if (!container.containsKey(className)) {
  29. Object object = Class.forName(className).newInstance();
  30. container.put(className, object);
  31. return object;
  32. }
  33. } catch (Exception e) {
  34. e.printStackTrace();
  35. }
  36. return container.get(className);
  37. }
  38. }
  39. public class ContainerSingletonThread implements Runnable {
  40. @Override
  41. public void run() {
  42. Object bean = ContainerSingleton.getBean("com.xy.blog.test.model.Person");
  43. System.out.println(bean);
  44. }
  45. }

ThreadLocal实现单例

需要注意的点:预防反射、序列化、克隆破坏单例
todo

测试

  1. public class SingletonTest {
  2. /**
  3. * 饿汉单例
  4. */
  5. @Test
  6. public void hungrySingletonTest() {
  7. Thread t1 = new Thread(new HungrySingletonThread());
  8. Thread t2 = new Thread(new HungrySingletonThread());
  9. t1.start();
  10. t2.start();
  11. System.out.println("end");
  12. }
  13. /**
  14. * 懒汉单例
  15. */
  16. @Test
  17. public void lazySingletonTest() {
  18. Thread t1 = new Thread(new LazySingletonTread());
  19. Thread t2 = new Thread(new LazySingletonTread());
  20. t1.start();
  21. t2.start();
  22. System.out.println("end");
  23. }
  24. /**
  25. * 懒汉单例 :线程安全 线程锁 锁类
  26. */
  27. @Test
  28. public void lazySyncSingletonTest() {
  29. Thread t1 = new Thread(new LazySyncSingletonTread());
  30. Thread t2 = new Thread(new LazySyncSingletonTread());
  31. t1.start();
  32. t2.start();
  33. System.out.println("end");
  34. }
  35. /**
  36. * 懒汉单例 : 方法锁 依旧线程不安全:单例被创建两次
  37. */
  38. @Test
  39. public void lazySyncSingletonTest2() {
  40. Thread t1 = new Thread(new LazySyncSingletonTread2());
  41. Thread t2 = new Thread(new LazySyncSingletonTread2());
  42. t1.start();
  43. t2.start();
  44. System.out.println("end");
  45. }
  46. /**
  47. * 懒汉单例:双重锁校验
  48. */
  49. @Test
  50. public void lazyDoubleCheckSyncSingletonTest() {
  51. Thread t1 = new Thread(new LazyDoubleCheckSyncSingletonTread());
  52. Thread t2 = new Thread(new LazyDoubleCheckSyncSingletonTread());
  53. t1.start();
  54. t2.start();
  55. try {
  56. Thread.sleep(2);
  57. } catch (InterruptedException e) {
  58. e.printStackTrace();
  59. }
  60. System.out.println("end");
  61. }
  62. /**
  63. * 饿汉式 单例 静态内部类
  64. */
  65. @Test
  66. public void innerSingletonTest() {
  67. try {
  68. Thread t1 = new Thread(new InnerSingletonTread());
  69. t1.start();
  70. Thread.sleep(1);
  71. reflect();
  72. Thread.sleep(1);
  73. System.out.println("end");
  74. } catch (InterruptedException e) {
  75. e.printStackTrace();
  76. }
  77. }
  78. /**
  79. * 反射暴力获取单例
  80. */
  81. @Test
  82. public void reflect() {
  83. try {
  84. Class<InnerSingleton> innerSingletonClass = InnerSingleton.class;
  85. Constructor<InnerSingleton> declaredConstructor = innerSingletonClass.getDeclaredConstructor();
  86. declaredConstructor.setAccessible(true);
  87. Field open = innerSingletonClass.getDeclaredField("open");
  88. open.setAccessible(true);
  89. open.set(null, true);
  90. InnerSingleton innerSingleton = declaredConstructor.newInstance();
  91. System.out.println(innerSingleton);
  92. } catch (Exception e) {
  93. e.printStackTrace();
  94. }
  95. }
  96. /**
  97. * 序列化破坏单例
  98. */
  99. @Test
  100. public void serializable() {
  101. InnerSingleton innerSingleton = InnerSingleton.getInstance();
  102. System.out.println(innerSingleton);
  103. InnerSingleton innerSingleton1 = JSONObject.parseObject(JSONObject.toJSONString(innerSingleton), InnerSingleton.class);
  104. System.out.println(innerSingleton1);
  105. try {
  106. //序列化
  107. FileOutputStream fileOutputStream = new FileOutputStream("temp");
  108. ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
  109. objectOutputStream.writeObject(innerSingleton);
  110. //反序列化
  111. FileInputStream fileInputStream = new FileInputStream("temp");
  112. ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
  113. InnerSingleton o = (InnerSingleton) objectInputStream.readObject();
  114. //打印结果
  115. System.out.println(innerSingleton == o);
  116. } catch (Exception e) {
  117. e.printStackTrace();
  118. }
  119. }
  120. @Test
  121. public void cloneDemo() {
  122. InnerSingleton innerSingleton = InnerSingleton.getInstance();
  123. try {
  124. InnerSingleton clone = (InnerSingleton) innerSingleton.clone();
  125. System.out.println(clone == innerSingleton);
  126. } catch (CloneNotSupportedException e) {
  127. e.printStackTrace();
  128. }
  129. }
  130. /**
  131. * 注册式单例
  132. */
  133. @Test
  134. public void register() {
  135. Thread t1 = new Thread(new RegisterSingletonThread());
  136. Thread t2 = new Thread(new RegisterSingletonThread());
  137. t1.start();
  138. t2.start();
  139. try {
  140. Thread.sleep(1);
  141. } catch (InterruptedException e) {
  142. e.printStackTrace();
  143. }
  144. System.out.println("end");
  145. }
  146. /**
  147. * 注册式单例 序列化破坏单例
  148. */
  149. @Test
  150. public void registerSerializable() {
  151. RegisterSingleton r1 = null;
  152. RegisterSingleton r2 = RegisterSingleton.getInstance();
  153. try {
  154. //序列化
  155. FileOutputStream fileOutputStream = new FileOutputStream("temp");
  156. ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
  157. objectOutputStream.writeObject(r2);
  158. //反序列化
  159. FileInputStream fileInputStream = new FileInputStream("temp");
  160. ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
  161. r1 = (RegisterSingleton) objectInputStream.readObject();
  162. //打印结果
  163. System.out.println(r1 == r2);
  164. } catch (Exception e) {
  165. e.printStackTrace();
  166. }
  167. }
  168. /**
  169. * 反射暴力获取单例
  170. */
  171. @Test
  172. public void registerReflect() {
  173. try {
  174. Class<RegisterSingleton> registerSingletonClass = RegisterSingleton.class;
  175. Constructor<RegisterSingleton> declaredConstructor = registerSingletonClass.getDeclaredConstructor();
  176. declaredConstructor.setAccessible(true);
  177. RegisterSingleton innerSingleton = declaredConstructor.newInstance();
  178. System.out.println(innerSingleton);
  179. } catch (Exception e) {
  180. e.printStackTrace();
  181. }
  182. }
  183. /**
  184. * 容器式 注册单例
  185. */
  186. @Test
  187. public void container() {
  188. Thread t1 = new Thread(new ContainerSingletonThread());
  189. Thread t2 = new Thread(new ContainerSingletonThread());
  190. t1.start();
  191. t2.start();
  192. try {
  193. Thread.sleep(5L);
  194. } catch (InterruptedException e) {
  195. e.printStackTrace();
  196. }
  197. System.out.println("end");
  198. // Object bean = ContainerSingleton.getBean("com.xy.blog.test.model.Person");
  199. // System.out.println(bean);
  200. }
  201. }

**