java设计模式之单例模式

背景:

  • 最近在看java设计模式,看了几篇关于“单例模式”的文章,决定自己实践一遍整理一下记录下来。

定义:

  • 在它的核心结构中只包含一个被称为单例的特殊类。通过单例模式可以保证系统中一个类只有一个实例。

特点:

  • 单例类只能有一个实例;
  • 单例类必须自己创建自己的唯一实例;
  • 单例类必须给其它对象提供这一实例。

要点:

  1. 私有构造方法;
  2. 指向自己实例的私有静态引用;
  3. 以自己实例为返回值的静态的公有方法。

优点:

  • 只存在一個實例,減少了內存的開支,特別是一個對象需要頻繁創建銷毀時,而且創建銷毀時性能又無法優化,單例模式的優勢就非常明顯;
  • 由於單例模式只存在一個實例,所以減少了系統的性能開銷,當一個單例對象產生時如果需要比較多的資源時,則可以在應用啟動時 * 直接生產一個單例,然後永駐內存的方式來解決;
  • 單例模式可以避免對資源的多重佔用,例如一個寫文件的操作,由於只存在一個實例在內存中,避免對同一個資源文件的同時寫操作;
  • 單例模式可以在系統設置全局的訪問點,優化和共享資源訪問,例如,可以設計一個單列類,負責所有數據表的映射處理。

缺点:

  • 單例模式一般沒有接口,擴展很困難,若要擴展,除了修改代碼基本上沒有第二種途徑可以實現;
  • 隐式使用引起类结构不清晰;
  • 單例對象如果持有Context,那麼很容易引起內存洩漏,此時需要傳給單例對象的Context最好是Application Context。

场景:

  • 需要频繁实例化然后销毁的对象;
  • 创建对象时耗时过多或者资源过多,但又经常用到的对象;
  • 资源共享的情况下,避免由于资源操作时导致的性能损耗;
  • 控制资源的情况下,方便资源之间的互相通信。

注意事项:

  • 只能使用单例类提供的方法获得单例对象,不能使用反射,否则会实例化出新对象;
  • 不要做断开单例类对象与类中静态引用的危险操作;
  • 多线程使用单例共享资源时,注意线程安全问题。

代码示范(单例类SingletonDemo):

  1. 第1种:懒汉式(线程不安全)
    1. 代码:

      	private static SingletonDemo instance;
      
      	private SingletonDemo() {
      
      	}
      
      	public static SingletonDemo getInstance() {
      		if (null == instance) {
      			instance = new SingletonDemo();
      		}
      		return instance;
      	}
      复制代码
    2. 优缺点:
      1. 优点:在用户第一次调用时才去初始化,节约资源,起到了懒加载的作用。
      2. 缺点:第一次调用时稍慢,因为要初始化,多线程不能正常工作。
  2. 第2种:懒汉(线程安全)
    1. 代码:

      	private static SingletonDemo instance;
      
      	private SingletonDemo() {
      	}
      
      	public static synchronized SingletonDemo getInstance() {
      		if (null == instance) {
      			instance = new SingletonDemo();
      		}
      		return instance;
      	}
      复制代码

    2. 优缺点:
      1. 优点:在多线程中能很好的工作。
      2. 缺点:每次调用getInstance()时都需要进行同步,大部分时候都是用不到同步的,造成了资源的浪费,所以不建议使用。
  3. 第3种:饿汉式(天生的线程安全)
    1. 代码:

      	private static SingletonDemo instance = new SingletonDemo();
      
      	private SingletonDemo() {
      	}
      
      	public static SingletonDemo getInstance() {
      		return instance;
      	}
      复制代码

    2. 优缺点:
      1. 优点:餓漢式在創建類的同時就創建了靜態實例供對象系統調用,以後不再發生改變, 所以是線程安全的。
      2. 缺点:
        1. 类加载时就完成了初始化,没有达到懒加载的效果;
        2. 在类加载时就初始化了实例,如果想在創建實例前調用某個方法給它傳遞一個參數就變不到了。
  4. 第4种:DCL(双重检查模式)
    1. 代码:

      	private volatile static SingletonDemo instance;
      
      	private SingletonDemo() {
      	}
      
      	public static SingletonDemo getInstance() {
      		if (null == instance) {
      			synchronized (SingletonDemo.class) {
      			}
      			if (null == instance) {
      				instance = new SingletonDemo();
      			}
      		}
      		return instance;
      	}    复制代码
    2. 实现原理:
    • 在getInstance()时对instance时进行了2次判空,第一次是为了不必要的同步,第二次是为了instance为null * 才创建实例。
  1. 优缺点:
    1. 优点:DCL的优点是资源利用率高,第一次执行getInstance()时实例对象才被实例化,效率高。
    2. 缺点:第一次加载时反应稍慢一点,而且有失效的可能。
第5种:静态内部类
  1. 代码:

    	private static class SingletonHolder {
    		private static final SingletonDemo INSTANCE = new SingletonDemo();
    	}
    
    	private SingletonDemo() {
    	}
    
    	public static final SingletonDemo getInstance() {
    		return SingletonHolder.INSTANCE;
    	}
    复制代码

  2. 实现原理:
    • 第一次加载Singleton类时并不会初始化instance,只有第一次调用getInstance()方法时 * 虚拟机加载SingleHolder并初始化instance,这样不仅能确保线程安全,也能保证实例的唯一性,很合理的单例模式。
第6种:枚举类SingletonEnum
  1. 代码:

    	INSTANCE;
    	public void whateverMethon() {
    		
    	}
    复制代码

  2. 优缺点:
    1. 优点:避免了线程安全,防止反序列化重新创建新的对象。
    2. 缺点:失去了类的一些特性,没有延时加载。
第7种:注册登记式
  1. 这个没看明白,不知道是我阅读的资料有问题还是自己理解力差。希望看到的小伙伴能给我讲一下,最好有可运行的代码示例。感激涕零!!!

总结:

  • 以上是阅读了几篇文章之后自己尝试写了几个小例子,毕竟“纸上得来终觉浅,绝知此事要躬行”嘛。

参阅资料,非常感激:

  1. https://blog.csdn.net/itachi85/article/details/50510124
  2. https://blog.csdn.net/coder_pig/article/details/54411894
  3. https://mp.weixin.qq.com/s?__biz=MzI4Njc5NjM1NQ==&mid=2247483786&idx=1&sn=072991244ec2f259c7049bc80317a728&scene=21#wechat_redirect



你可能感兴趣的:(java设计模式之单例模式)