ToB企服应用市场:ToB评测及商务社交产业平台

标题: 设计模式——单例模式 [打印本页]

作者: 大号在练葵花宝典    时间: 2022-9-1 09:09
标题: 设计模式——单例模式
引言

  今天来谈谈设计模式中的单例模式,温故知新,以免生疏。
  软件设计领域的四位世界级大师Gang Of Four (GoF):Erich Gamma,Richard Helm,Ralph Johnson,John Vlissides四人合著了《Design Patterns - Elements of Reusable Object-Oriented Software》一书,(中文译名:《设计模式:可复用面向对象软件的基础》)。该书首次提到了软件开发中设计模式的概念,对面向对象软件设计产生了巨大影响。
  单例模式属于创建型模式,那么这里就要简述一下创建型模式。顾名思义,就是创建对象的设计模式。频繁地使用基本对象创建方式(比如new操作)会使系统的耦合性变高,导致某些设计上的问题。创建型模式对类的实例化进行抽象,将对象的创建与对象的使用分离,隐藏了类的实例化过程。
  在系统中,有一些对象其实只需要一个,例如线程池、缓存、注册表、日志对象、充当打印机显卡等设备驱动程序的对象。同时这些类比较庞大复杂,并且这些对象完全可以复用。若创建多个实例或频繁创建销毁实例对象,会导致程序行为异常、资源使用过量、或者不一致性的结果,这就有了单例模式。
类的构成

实现方式

1. 懒汉式(线程不安全)
  1. public class Singleton {  
  2.     private static Singleton instance;  //声明静态变量
  3.     private Singleton (){}   //构造器
  4.   
  5.     public static Singleton getInstance() {  
  6.         if (instance == null) {  
  7.             instance = new Singleton();  
  8.         }  
  9.         return instance;  
  10.     }  
  11. }
复制代码
2. 懒汉式(线程安全)
  1. public class Singleton {  
  2.     private static Singleton instance;  
  3.     private Singleton (){}  
  4.     public static synchronized Singleton getInstance() {  //使用同步方法
  5.         if (instance == null) {  
  6.             instance = new Singleton();  
  7.         }  
  8.         return instance;  
  9.     }  
  10. }
复制代码
3. 饿汉式(线程安全)
  1. public class Singleton {  
  2.     private static Singleton instance = new Singleton();  //类加载时就进行实例化
  3.     private Singleton (){}  
  4.     public static Singleton getInstance() {  
  5.     return instance;  
  6.     }  
  7. }
复制代码
注:懒汉式与饿汉式最主要的区别在于创建单例的时机不同,懒汉式根据是否需要实例,手动创建;饿汉式在类加载时自动创建单例
4. 双重校验锁方式(线程安全)
  1. public class Singleton {
  2.     private static Singleton Instance;
  3.     private Singleton() {}
  4.     public static Singleton getInstance() {
  5.         if (Instance == null) {
  6.             synchronized (Singleton.class) {  //在需要构建单例的时候给Class对象加锁
  7.                Instance = new Singleton();
  8.             }
  9.         }
  10.         return Instance;
  11.     }
  12. }
复制代码
问题:在多个线程执行判断条件时,虽然只有一个线程能够抢到锁取创建单例,但是可能有其他线程已经进入了if代码块,之后会再进行if判断了,而这些线程等待释放锁后,随即又会创建实例对象,最终实例会被多次被创建。显然线程不安全。
  1. public class Singleton {
  2.     private static Singleton Instance;
  3.     private Singleton() {}
  4.     public static Singleton getInstance() {
  5.         if (Instance == null) {
  6.             synchronized (Singleton.class) {  //在需要构建单例的时候给Class对象加锁
  7.             if (Instance == null) {          //增加了判空条件
  8.                         Instance = new Singleton();
  9.                     }
  10.             }
  11.         }
  12.         return Instance;
  13.     }
  14. }
复制代码
  1. public class Singleton {  
  2.     private volatile static Singleton Instance;  //增加volatile关键字,防止JVM指令重排
  3.     private Singleton (){}  
  4.    
  5.     public static Singleton getInstance() {  
  6.     if (Instance == null) {  
  7.         synchronized (Singleton.class) {  
  8.             if (Instance == null) {  
  9.                 Instance = new Singleton();  
  10.             }  
  11.         }  
  12.     }  
  13.     return singleton;  
  14.     }  
  15. }
复制代码
5.静态内部类方式
  1. public class Singleton {
  2.     private Singleton() {
  3.     }
  4.         //静态内部类
  5.     private static class SingletonHolder {
  6.         private static final Singleton INSTANCE = new Singleton();
  7.     }
  8.     public static Singleton getInstance() {  
  9.         return SingletonHolder.INSTANCE;    //访问静态内部类中静态成员
  10.     }
  11. }
复制代码
6.枚举方式
  1. public enum Singleton {  
  2.     INSTANCE;  
  3.     public void whateverMethod() {  //任意方法
  4.     }  
  5. }
复制代码
结语

  一般情况下,不建议使用两种懒汉式实现单例模式;明确使用静态方法和实现懒加载效果时,会采用静态内部类方式;涉及到反序列化创建对象的时候,可以使用枚举方式;一般而言,饿汉式以及双重校验锁比较常用。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4