溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java的單例模式如何實現

發布時間:2022-02-23 15:31:20 來源:億速云 閱讀:191 作者:iii 欄目:開發技術

這篇文章主要介紹“Java的單例模式如何實現”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“Java的單例模式如何實現”文章能幫助大家解決問題。

什么是單例模式

  • 單例模式(Singleton Pattern)是一個比較簡單的模式,實際應用很廣泛,比如 Spring 中的Bean實例就是一個單例對象。

  • 定義:確保某一個類 只有一個實例,而且自行實例化并向整個系統提供這個實例。

單例模式的優缺點

優點

  • 只有一個實例,減少了內存的開銷,尤其是頻繁的創建和銷毀實例。

  • 單例模式可以避免對資源的多重占用,例如一個寫文件動作,由于只有一個實例存在內存中,避免對同一個資源文件的同時寫操作。

  • 單例模式可以在系統設置全局的訪問點,優化和共享資源訪問,例如可以設計一個單例類,負責所有數據表的映射處理。

缺點

  • 單例模式一般沒有接口,很難擴展(根據環境而定)。

  • 單例模式與單一職責原則有沖突。一個類應該只實現一個邏輯,而不關心是否是單例的。

單例模式的實現

  • 單例模式有很多的實現方式,但是各種實現的方式都有其優缺點,下面來看看各種的實現方式。

  • 單例模式的實現滿足以下幾點:構造方法私有。有一個靜態方法獲取該類的實例。該類保證只有一個實例。

懶漢式

  • 懶漢式是當用到這個對象的時候才會創建。

  • 懶漢式,在需要單例模式類實例時它才創建出來給你(因為很懶)。

  • 優點:只有用到的時候才會創建這個對象,因此節省資源。

  • 簡單的實現如下:

/**
  *Singleton類,單例模式類,在類加載時便會創建一個私有靜態變量instance,也就是該類的實
  *例,再通過公共接口getInstance()來發布該實例
  */
public class Singleton {  
    private static Singleton instance;
    //私有化構造方法防止外界new對象
    private Singleton (){

    }

    //公有化靜態函數,對外暴露單例對象的接口

    public static Singleton getInstance() {

        if (instance == null) {

            instance = new Singleton();

        }

        return instance;

    }

但是這種方式并不能保證這是唯一的單例,在高并發訪問下,多個線程同時訪問到這個單例時,還是有可能不能保證這個類就是單例的

為了保證線程安全,我們可以加鎖,給這個getInstance()方法加上線程同步鎖synchronize具體實現如下:

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

但是這種方式一旦加鎖,雖然可以保證其實單例且線程安全的,但是在高并發訪問下性能必然是受到影響,多個線程都需要用到該單例時,就無法保證速度,需要同步地等待這個單例使用完回到JVM中的堆區(Heap)才可以繼續使用這個單例,效率十分的低。

還有一種是雙重檢查式,兩次判斷

Double Check Lock(DCL)方式實現單例模式

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

我們可以看到getInstance中對instance進行了兩次判斷是否為空,第一次判斷主要是為了避免不必要的同步問題,第二次判斷則是為了在null的情況下創建實例,因為在某些情況下會出現失效問題即DCL失效問題,可以使用volatile關鍵字處理這個問題,但是同樣的,使用了volatile關鍵字也會對性能有一定的影響。但是優點在于資源利用率高,第一次執行getInstance時對象才被實例化,但是DCL也因為第一次加載時反應慢,所以在高并發情況下也會有一定的缺陷。

餓漢式

  • 餓漢式和懶漢式恰巧相反,在類加載的時候就創建實例。

  • 單例模式類迫不及待的想要創建實例了(因為餓了)

  • 優點:還沒用到就創建,浪費資源。

  • 缺點:在類加載的時候就創建,線程安全。

  • 實現如下:

/**  *這種方式在類加載時就完成了初始化,所以類加載較慢,但是獲取對象的速度快。這種方式  *基于類加載機制,避免了多線程的同步問題。如果從來沒有使用過這個實例,則會造成內存  *的浪費。  */public class Singleton {      private static Singleton instance = new Singleton();      private Singleton (){            }      public static Singleton getInstance() {      	return instance;      }  }

匿名內部類/靜態內部類

  • 利用靜態變量、靜態代碼塊、靜態方法都是在類加載的時候只加載一次的原理。

  • 實現如下

public class Singleton {    private static Singleton instance;    //靜態塊在類加載時會被執行,也就創建了Singleton類實例    static{        instance = new Singleton();    }    private Singleton (){        }      public static final Singleton getInstance() {      	return SingletonHolder.INSTANCE;      }  }
/**  *Java靜態內部類的特性是,加載的時候不會加載內部靜態類,使用的時候才會進行加載。  *第一次加載Singleton類時并不會初始化sInstance,只有第一次調用getInstance方法時虛  *擬機加載SingletonHolder并初始化sInstance。這樣不僅能確保線程安全,也能保證  *Singleton類的唯一性。所以,推薦使用靜態內部類單例模式  */public class Singleton {      private static class SingletonHolder {      	private static final Singleton INSTANCE = new Singleton();      }    private Singleton (){        }      public static final Singleton getInstance() {      	return SingletonHolder.INSTANCE;      }  }

枚舉單例模式

/**
  *默認枚舉實例的創建是線程安全的,并且在任何情況下都是單例。
  *枚舉單例的有點就是簡單,缺點是可讀性不高。
  */
public enum Singleton {
    //外部調用由原來的Singleton.getInstance變成了Singleton.INSTANCE了。
    INSTANCE;
}

總結

單例模式是運用頻率很高的模式,在我們客戶端通常是沒有高并發的情況,所以選擇哪種方式并不會有太大的影響。出于效率考慮,推薦使用靜態內部類的單例模式和DCL的單例模式。

優點:

  • 由于單例模式在內存中只有一個實例,減少內存開支,特別是一個對象需要頻繁創建、銷毀時,而且創建或銷毀時性能又無法優化,單例模式的優勢就十分明顯。

  • 由于單例模式只生成一個實例,所以減少了系統的性能開銷,當一個對象的產生需要比較多的資源時,如讀取配置、產生其他依賴對象時,則可通過在應用啟動時直接產生一個單例對象,然后用永久駐留的方式解決。

  • 單例模式可以避免對資源的多重占用,如一個文件的操作,由于只有一個實例存在內存中,避免對同一個資源文件的同時操作。

  • 單例模式可以在系統設置全局的訪問點,優化和共享資源訪問。例如,可以設計一個單例類,負責所有數據表的映射處理。

缺點:

  • 單例模式一般沒有接口,擴展很困難,除非修改代碼。

  • 單例對象如果持有Context,那么很容易引發內存泄露,此時需要注意傳遞給單例對象的Context最好是Application Context。

  • 不適合用于變化頻繁的對象;如果實例化的對象長時間不被利用,系統會認為該對象是垃圾而被回收,這可能會導致對象狀態的丟失;

使用場景

  • 網站訪問量計數器。

  • 項目中用于讀取配置文件的類。

  • Spring中,每個Bean默認都是單例的,這樣便于Spring容器進行管理。

關于“Java的單例模式如何實現”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

亚洲午夜精品一区二区_中文无码日韩欧免_久久香蕉精品视频_欧美主播一区二区三区美女