欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

JAVA破壞單例模式的方式以及避免方法

 更新時(shí)間:2020年06月16日 11:32:04   作者:宋者為王  
這篇文章主要介紹了JAVA破壞單例模式的方式以及避免方法,文中講解非常細(xì)致,代碼幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下

      單例模式,大家恐怕再熟悉不過了,其作用與實(shí)現(xiàn)方式有多種,這里就不啰嗦了。但是,咱們在使用這些方式實(shí)現(xiàn)單例模式時(shí),程序中就真的會只有一個(gè)實(shí)例嗎?

      聰明的你看到這樣的問話,一定猜到了答案是NO。這里筆者就不賣關(guān)子了,開門見山吧!實(shí)際上,在有些場景下,如果程序處理不當(dāng),會無情地破壞掉單例模式,導(dǎo)致程序中出現(xiàn)多個(gè)實(shí)例對象。

      下面筆者介紹筆者已知的三種破壞單例模式的方式以及避免方法。

1、反射對單例模式的破壞

      我們先通過一個(gè)例子,來直觀感受一下

    (1)案例

  DCL實(shí)現(xiàn)的單例模式:

public class Singleton{
  private static volatile Singleton mInstance;
  private Singleton(){}
  public static Singleton getInstance(){
    if(mInstance == null){
      synchronized (Singleton.class) {
        if(mInstance == null){
          mInstance = new Singleton();
        }
      }
    }
    return mInstance;
  }
}

測試代碼:

public class SingletonDemo {

  public static void main(String[] args){
    Singleton singleton = Singleton.getInstance();
    try {
      Constructor<Singleton> constructor = Singleton.class.getDeclaredConstructor();
      constructor.setAccessible(true);
      Singleton reflectSingleton = constructor.newInstance();
      System.out.println(reflectSingleton == singleton);
    } catch (Exception e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
  }
}

執(zhí)行結(jié)果:

false

      運(yùn)行結(jié)果說明,采用反射的方式另辟蹊徑實(shí)例了該類,導(dǎo)致程序中會存在不止一個(gè)實(shí)例。

    (2)解決方案

      其思想就是采用一個(gè)全局變量,來標(biāo)記是否已經(jīng)實(shí)例化過了,如果已經(jīng)實(shí)例化過了,第二次實(shí)例化的時(shí)候,拋出異常。實(shí)現(xiàn)代碼如下:

public class Singleton{
  private static volatile Singleton mInstance;
  private static volatile boolean mIsInstantiated = false;
  private Singleton(){
    if (mIsInstantiated){
      throw new RuntimeException("Has been instantiated, can not do it again!");
    }
    mIsInstantiated = true;
  }
  public static Singleton getInstance(){
    if(mInstance == null){
      synchronized (Singleton.class) {
        if(mInstance == null){
          mInstance = new Singleton();
        }
      }
    }
    return mInstance;
  }
}

執(zhí)行結(jié)果:

2、clone()對單例模式的破壞

       當(dāng)需要實(shí)現(xiàn)單例的類允許clone()時(shí),如果處理不當(dāng),也會導(dǎo)致程序中出現(xiàn)不止一個(gè)實(shí)例。

    (1)案例

  一個(gè)實(shí)現(xiàn)了Cloneable接口單例類:

public class Singleton implements Cloneable{
  private static volatile Singleton mInstance;
  private Singleton(){
  }
  public static Singleton getInstance(){
    if(mInstance == null){
      synchronized (Singleton.class) {
        if(mInstance == null){
          mInstance = new Singleton();
        }
      }
    }
    return mInstance;
  }
  @Override
  protected Object clone() throws CloneNotSupportedException {
    // TODO Auto-generated method stub
    return super.clone();
  }
}

測試代碼:

public class SingletonDemo {

  public static void main(String[] args){
    try {
      Singleton singleton = Singleton.getInstance();
      Singleton cloneSingleton;
      cloneSingleton = (Singleton) Singleton.getInstance().clone();
      System.out.println(cloneSingleton == singleton);
    } catch (CloneNotSupportedException e) {
      e.printStackTrace();
    }
  }
}

執(zhí)行結(jié)果:

false

  (2)解決方案:

     解決思想是,重寫clone()方法,調(diào)clone()時(shí)直接返回已經(jīng)實(shí)例的對象

public class Singleton implements Cloneable{
  private static volatile Singleton mInstance;
  private Singleton(){
  }
  public static Singleton getInstance(){
    if(mInstance == null){
      synchronized (Singleton.class) {
        if(mInstance == null){
          mInstance = new Singleton();
        }
      }
    }
    return mInstance;
  }
  @Override
  protected Object clone() throws CloneNotSupportedException {
    return mInstance;
  }
}

執(zhí)行結(jié)果:

true

3、序列化對單例模式的破壞

   在使用序列化/反序列化時(shí),也會出現(xiàn)產(chǎn)生新實(shí)例對象的情況。

  (1)案例

      一個(gè)實(shí)現(xiàn)了序列化接口的單例類:

public class Singleton implements Serializable{
  private static volatile Singleton mInstance;
  private Singleton(){
  }
  public static Singleton getInstance(){
    if(mInstance == null){
      synchronized (Singleton.class) {
        if(mInstance == null){
          mInstance = new Singleton();
        }
      }
    }
    return mInstance;
  }
}

測試代碼:

public class SingletonDemo {

  public static void main(String[] args){
    try {
      Singleton singleton = Singleton.getInstance();
      FileOutputStream fos = new FileOutputStream("singleton.txt");
      ObjectOutputStream oos = new ObjectOutputStream(fos);
      oos.writeObject(singleton);
      oos.close();
      fos.close();

      FileInputStream fis = new FileInputStream("singleton.txt");
      ObjectInputStream ois = new ObjectInputStream(fis);
      Singleton serializedSingleton = (Singleton) ois.readObject();
      fis.close();
      ois.close();
      System.out.println(serializedSingleton==singleton);
    } catch (Exception e) {
      e.printStackTrace();
    }

  }
}

     運(yùn)行結(jié)果:

false

    (2)解決方案

    在反序列化時(shí)的回調(diào)方法 readResolve()中返回單例對象。

public class Singleton implements Serializable{
  private static volatile Singleton mInstance;
  private Singleton(){
  }
  public static Singleton getInstance(){
    if(mInstance == null){
      synchronized (Singleton.class) {
        if(mInstance == null){
          mInstance = new Singleton();
        }
      }
    }
    return mInstance;
  }

  protected Object readResolve() throws ObjectStreamException{
    return mInstance;
  }
}

結(jié)果:

true

       以上就是筆者目前已知的三種可以破壞單例模式的場景以及對應(yīng)的解決辦法,讀者如果知道還有其他的場景,記得一定要分享出來噢,正所謂“獨(dú)樂樂不如眾樂樂”!?。?/p>

       單例模式看起來是設(shè)計(jì)模式中最簡單的一個(gè),但“麻雀雖小,五臟俱全”,其中有很多細(xì)節(jié)都是值得深究的。即便是本篇介紹的這幾個(gè)場景,也只是介紹了一些梗概而已,很多細(xì)節(jié)還需要讀者自己去試驗(yàn)和推敲的,比如:通過枚舉方式實(shí)現(xiàn)單例模式,就不存在上述問題,而其它的實(shí)現(xiàn)方式似乎都存在上述問題!

       后記

       本篇參(剽)考(竊)了如下資料:http://www.dbjr.com.cn/article/143047.htm

以上就是JAVA破壞單例模式的方式以及避免方法的詳細(xì)內(nèi)容,更多關(guān)于JAVA 單例模式的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Java實(shí)現(xiàn)抽獎(jiǎng)功能

    Java實(shí)現(xiàn)抽獎(jiǎng)功能

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)抽獎(jiǎng)功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • 詳解springboot如何更新json串里面的內(nèi)容

    詳解springboot如何更新json串里面的內(nèi)容

    這篇文章主要為大家介紹了springboot 如何更新json串里面的內(nèi)容,文中有詳細(xì)的解決方案供大家參考,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2023-10-10
  • SpringBoot如何切換成其它的嵌入式Servlet容器(Jetty和Undertow)

    SpringBoot如何切換成其它的嵌入式Servlet容器(Jetty和Undertow)

    這篇文章主要介紹了SpringBoot如何切換成其它的嵌入式Servlet容器(Jetty和Undertow),具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • Spring boot監(jiān)控Actuator-Admin實(shí)現(xiàn)過程詳解

    Spring boot監(jiān)控Actuator-Admin實(shí)現(xiàn)過程詳解

    這篇文章主要介紹了Spring boot監(jiān)控Actuator-Admin實(shí)現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • java中跨域問題解決的幾種方式

    java中跨域問題解決的幾種方式

    這篇文章主要給大家介紹了關(guān)于java中跨域問題解決的幾種方式, 在前后端分離項(xiàng)目中,經(jīng)常會遇到跨域問題,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-07-07
  • java后臺調(diào)用接口及處理跨域問題的解決

    java后臺調(diào)用接口及處理跨域問題的解決

    這篇文章主要介紹了java后臺調(diào)用接口,處理跨域的問題及解決,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java 自定義Spring框架與核心功能詳解

    Java 自定義Spring框架與核心功能詳解

    Spring框架是由于軟件開發(fā)的復(fù)雜性而創(chuàng)建的。Spring使用的是基本的JavaBean來完成以前只可能由EJB完成的事情。然而,Spring的用途不僅僅限于服務(wù)器端的開發(fā)
    2021-10-10
  • Spring Boot全局異常處理解析

    Spring Boot全局異常處理解析

    這篇文章主要為大家詳細(xì)介紹了Spring Boot全局異常處理的相關(guān)資料,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • springsecurity 基本使用詳解

    springsecurity 基本使用詳解

    這篇文章主要介紹了springsecurity 基本使用,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • MyBatis開啟二級緩存實(shí)現(xiàn)過程解析

    MyBatis開啟二級緩存實(shí)現(xiàn)過程解析

    這篇文章主要介紹了MyBatis開啟二級緩存實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-07-07

最新評論