單例模式

單例模式是最常用到的設(shè)計模式之一,熟悉設(shè)計模式的朋友對單例模式都不會陌生。

因為設(shè)計模式講究對象之間的關(guān)系的抽象,而單例模式只有自己一個對象,也因此有些設(shè)計大師并把把其稱為設(shè)計模式之一。

簡介

單例模式是一種常用的軟件設(shè)計模式,其定義是單例對象的類只能允許一個實例存在。

應(yīng)用場景

1. Windows的Task Manager(任務(wù)管理器)就是很典型的單例模式(這個很熟悉吧),想想看,是不是呢,你能打開兩個windows task manager嗎? 不信你自己試試看哦~?

2. windows的Recycle Bin(回收站)也是典型的單例應(yīng)用。在整個系統(tǒng)運行過程中,回收站一直維護著僅有的一個實例。所有桌面上面的東西,比如視頻,文件等等,刪除之后都會進入到它里面.專業(yè)術(shù)語講:就是始終是一個對象實例.

3、火車站買票,多個窗口同時去打印車票,但是車票數(shù)量就是這么多,防止出現(xiàn)超售。當(dāng)需要對同一個資源進行利用時,就好比火車賣票,就那么一堆資源,需要多個線程進行處理,而單例就可以解決了,

4、一個播放器程序,當(dāng)用戶打開一個播放音樂界面,再想打開另一個音樂播放時,之前的界面就關(guān)閉了。這就是一個單利模式的具體應(yīng)用

5、java Runtime 類:Runtime類本身就是單例設(shè)計模式的一種應(yīng)用,因為整個JVM中只存在一個Runtime類的對象,可以使用Runtime類取得JVM的系統(tǒng)信息,或者使用gc()方法釋放掉垃圾空間,還可以運行本機的程序。

Runtime 代表著Java程序的運行時環(huán)境,每個Java程序都有一個Runtime實例,該類會被自動創(chuàng)建,我們可以通過Runtime.getRuntime()?方法來獲取當(dāng)前程序的Runtime實例。

基本的實現(xiàn)思路

單例模式要求類能夠有返回對象一個引用(永遠是同一個)和一個獲得該實例的方法(必須是靜態(tài)方法,通常使用getInstance這個名稱)。

單例的實現(xiàn)主要是通過以下兩個步驟:

將該類的構(gòu)造方法定義為私有方法,這樣其他處的代碼就無法通過調(diào)用該類的構(gòu)造方法來實例化該類的對象,只有通過該類提供的靜態(tài)方法來得到該類的唯一實例;

在該類內(nèi)提供一個靜態(tài)方法,當(dāng)我們調(diào)用這個方法時,如果類持有的引用不為空就返回這個引用,如果類保持的引用為空就創(chuàng)建該類的實例并將實例的引用賦予該類保持的引用。

餓漢式&懶漢式

單例中懶漢和餓漢的區(qū)別在于以下幾點:

  1、餓漢式是線程安全的,在類創(chuàng)建的同時就已經(jīng)創(chuàng)建好一個靜態(tài)的對象供系統(tǒng)使用,以后不在改變。懶漢式如果在創(chuàng)建實例對象時不加上synchronized則會導(dǎo)致對對象的訪問不是線程安全的。

  2、從實現(xiàn)方式來講他們最大的區(qū)別就是懶漢式是延時加載,他是在需要的時候才創(chuàng)建對象,而餓漢式在虛擬機啟動的時候就會創(chuàng)建,餓漢式無需關(guān)注多線程問題、寫法簡單明了、能用則用

懶漢和餓漢的本質(zhì)區(qū)別,就是實例化對象的時機,即是什么時候?qū)ο髣?chuàng)建起來

懶漢模式:


1、餓漢式(靜態(tài)常量)

可以防止多線程訪問生成兩個不一樣的實例。

上面已經(jīng)實例化了,但是一直沒有被調(diào)用,會導(dǎo)致內(nèi)存浪費

public class Singleton {

? ? private final static Singleton INSTANCE = new Singleton();

? ? private Singleton(){}

? ? public static Singleton getInstance(){

? ? ? ? return INSTANCE;

? ? }

}

2、餓漢式(靜態(tài)代碼塊)

public class Singleton {

? ? private static volatile?Singleton instance;

? ? static {

? ? ? ? instance = new Singleton();

? ? }

? ? private Singleton() {}

? ? public Singleton getInstance() {

? ? ? ? return instance;

? ? }

}

3、懶漢式(線程不安全)

這種寫法起到了Lazy Loading的效果,但是只能在單線程下使用。如果在多線程下,一個線程進入了if (singleton == null)判斷語句塊,還未來得及往下執(zhí)行,另一個線程也通過了這個判斷語句,這時便會產(chǎn)生多個實例。所以在多線程環(huán)境下不可使用這種方式。

public class Singleton {

? ? private static Singleton singleton;

? ? private Singleton() {}

? ? public static volatile?Singleton getInstance() {

? ? ? ? if (singleton == null) {

? ? ? ? ? ? singleton = new Singleton();

? ? ? ? }

? ? ? ? return singleton;

? ? }

}

4、懶漢式(線程安全,同步方法)

使用synchronized?實現(xiàn)了線程同步。 但是較耗時。每個線程在想獲得類的實例時候,執(zhí)行g(shù)etInstance()方法都要進行同步。而其實這個方法只執(zhí)行一次實例化代碼就夠了,后面的想獲得該類實例,直接return就行了。

public class Singleton {

? ? private static Singleton singleton;

? ? private Singleton() {}

? ? public static synchronized Singleton getInstance() {

? ? ? ? if (singleton == null) {

? ? ? ? ? ? singleton = new Singleton();

? ? ? ? }

? ? ? ? return singleton;

? ? }

}

5、懶漢式(線程安全,同步代碼塊)

第3種實現(xiàn)方式遇到的情形一致,假如一個線程進入了if (singleton == null)判斷語句塊,還未來得及往下執(zhí)行,另一個線程也通過了這個判斷語句,這時便會產(chǎn)生多個實例。

public class Singleton {

? ? private static Singleton singleton;

? ? private Singleton() {}

? ? public static Singleton getInstance() {

? ? ? ? if (singleton == null) {

? ? ? ? ? ? synchronized (Singleton.class) {

? ? ? ? ? ? ? ? singleton = new Singleton();

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? return singleton;

? ? }

}

6、雙重檢查

進行了兩次if (singleton == null)檢查,這樣就可以保證線程安全了。這樣,實例化代碼只用執(zhí)行一次,后面再次訪問時,判斷if (singleton == null),直接return實例化對象。

public class Singleton {

? ? private static volatile Singleton singleton;

? ? private Singleton() {}

? ? public static Singleton getInstance() {

? ? ? ? if (singleton == null) {

? ? ? ? ? ? synchronized (Singleton.class) {

? ? ? ? ? ? ? ? if (singleton == null) {

? ? ? ? ? ? ? ? ? ? singleton = new Singleton();

? ? ? ? ? ? ? ? }

? ? ? ? ? ? }

? ? ? ? }

? ? ? ? return singleton;

? ? }

}

7、靜態(tài)內(nèi)部類

延遲加載:采用了類裝載的機制來保證初始化實例時只有一個線程。靜態(tài)內(nèi)部類方式在Singleton類被裝載時并不會立即實例化,而是在需要實例化時,調(diào)用getInstance方法,才會裝載SingletonInstance類,從而完成Singleton的實例化。

public class Singleton {

? ? private Singleton() {}

? ? private static class SingletonInstance {

? ? ? ? private static final Singleton INSTANCE = new Singleton();

? ? }

? ? public static Singleton getInstance() {

? ? ? ? return SingletonInstance.INSTANCE;

? ? }

}

8、枚舉單例

系統(tǒng)內(nèi)存中該類只存在一個對象,節(jié)省了系統(tǒng)資源,對于一些需要頻繁創(chuàng)建銷毀的對象

public enum EnumSingleton {

INSTANCE;

? ? private Resourceinstance;

? ? EnumSingleton() {

instance =new Resource();

? ? }

public ResourcegetInstance() {

return instance;

? ? }

}

拓展:

volatile 與 synchronzed

volatile?只能修飾變量。synchronzed還可修飾方法

synchronized不僅保證可見性,而且還保證原子性

volatile?保證可見性,但不能保證原子性。

參考:http://www.cnblogs.com/Mainz/p/3556430.html#

https://www.cnblogs.com/zhaoyan001/p/6365064.html

工廠模式:http://blog.csdn.net/zxt0601/article/details/52798423

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容