DP Singleton設計模式

2021-07-16 07:19:28 字數 2772 閱讀 2349

單例模式:單例模式是一種常用的軟體設計模式。在它的核心結構中只包含乙個被稱為單例的特殊類。通過單例模式可以保證系統中乙個類有且只有乙個例項。

單例模式最初的定義出現於《設計模式》:「保證乙個類僅有乙個例項,並提供乙個訪問它的全域性訪問點。」

乙個系統中可以存在多個列印任務,但是只能有乙個正在工作的任務;乙個系統只能有乙個視窗管理器或檔案系統;乙個系統只能有乙個計時工具或id(序號)生成器。如在windows中就只能開啟乙個任務管理器。如果不使用機制對視窗物件進行唯一化,將彈出多個視窗,如果這些視窗顯示的內容完全一致,則是重複物件,浪費記憶體資源;如果這些視窗顯示的內容不一致,則意味著在某一瞬間系統有多個狀態,與實際不符,也會給使用者帶來誤解,不知道哪乙個才是真實的狀態。因此有時確保系統中某個物件的唯一性即乙個類只能有乙個例項非常重要。

單例模式的特點:

1、單例類只能有乙個例項。

2、單例類必須自己建立自己的唯一例項。

3、單例類必須給所有其他物件提供這一例項。

首先我們從乙個簡單的單例模式(餓漢式)開始構建:

餓漢式:

class usbdriver 

public static usbdriver getinstance()

}

首先什麼是餓漢式呢,我們都知道乙個餓漢肯定是對事物渴求,也就是對某種資源渴求的。所以我們的餓漢單例模式 也就是對 單例十分的渴求

渴求到什麼程度呢,當類裝載進來的時候 就立即著手構建我們的例項了。這裡private的建構函式,是防治new出來,這樣就不是單例了。

這裡需要問乙個問題,這會不會引起執行緒安全問題?

答案是不會,因為在usbdriver類初始化時,就已經載入進來了,所以在呼叫getinstance()時候,並不會產生執行緒安全問題,可以說天生就是執行緒安全的。

如果我們的驅動程式比較耗費資源,如果我們可能會用到幾十種甚至更多的驅動程式的話,那麼我們對於這種餓漢單例模式是不是需要進行一些改進,

使的當我們真正需要該例項的時候才初始化,那麼我們什麼時候才真正需要該例項呢?就是我們呼叫getinstance()的時候。

class usbdriver 

public static synchronized usbdriver getinstance()

return driver;

}}

好的,這次我們再一次改進,對於該單例我們採取了懶載入策略(懶漢式),直到需要用的時候才構建。

這裡我們給整個getinstance()方法使用了synchronized 來鎖定該方法。

這樣同樣帶乙個問題,就是因為鎖的粒度是方法級的,所以對於多於多執行緒效能會產生很大的問題。

所以我們可以將鎖適當的細化,將鎖移至內部,採用更小的鎖塊來進行優化(雙重檢查鎖定式)。

class usbdriver 

public static usbdriver getinstance()

}} return driver;

}}

這裡我們在driver 裡面加了 volatile 修飾,這是為了保證讀和取都是在保證不會被多執行緒打斷,這是一種保護措施,保證獲得driver 的最新資訊。

為什麼要採用雙重檢查策略呢?考慮一種情況,當我乙個執行緒執行到 if(driver ==null)的時候,這個時候driver還沒初始化,如果不採用雙重檢查的話,我讀到了driver =null,但是這個時候有乙個執行緒搶險進行到了同步**塊。

當driver 構建之後,之前的執行緒因為讀到了 driver = null,實際上這個時候driver 並不是null了

這就無異帶來了執行緒安全問題,而且更糟糕的是,可能會產生引用逸出。

即 我乙個執行緒先 呼叫getinstance獲得了乙個driver,然後後乙個執行緒產生上述分析的情況,重新new 了乙個driver。這個時候就破壞了有且只有乙個的特性。

事實上,這種雙重檢查鎖定策略,在concurrenthashmap也是有類似的設計的。

那麼有沒有辦法避免同步**塊呢?

是可以的,不過這利用到jvm保證每個類只被載入一次的特性。

在我們的驅動類內增加乙個內部內,該內部類持有驅動例項,但是該例項,只有在該類被載入的時候才會真正的初始化。

class usbdriver 

private static class usbdriverholder

public static usbdriver getinstance()

}

這種方式稱為靜態內部類單例,該方法無疑在簡潔性,效能上都有很大的優勢,但是有個弊端,就是必須對驅動類進行大的結構變動。很多情況下,我們無法改動**內部原始碼,

比如引入外部的jar。

看看spring中的單例:

defaultsingletonbeanregistry類中的getsingleton方法

protected object getsingleton(string beanname, boolean allowearlyreference) }}

} return (singletonobject != null_object ? singletonobject : null);

}

我們可以看到spring中對於單例似乎是用了我們的懶載入的 雙重檢查鎖定。

這裡spring 採取雙重檢查鎖定也是有一定原因的。如果使用懶漢式勢必帶來執行效率的降低,

如果採用靜態內部類單例,必須去改動原始碼。spring 並不會侵入你的**。

設計模式 設計模式

物件導向程式設計 oop 的基本概念有 封裝,抽象,繼承,多型等,如何開發出可復用的物件導向軟體一直困擾著軟體開發人員。可復用的物件導向技術包括類的繼承,物件的組合和引數化型別 generic gof的巨著 設計模式 總結出可復用的物件導向的23個設計模式,並且歸類成 建立型模式,結構型模式和行為型...

設計模式 命令設計模式

一句話總結 命令設計模式的實質是將命令定義,命令的執行分離開,從而提公升了系統的解藕性 結構 命令的抽象command 命令的具體實現concretecommand 命令處理者抽象ireceiver 命令處理者的具體實現concretereceiver 命令的呼叫者invoker 客戶端client...

設計模式 9 設計模式

文章 head first 第一章 head first 設計模式讀書筆記 1 策略模式 觀察者模式 head first設計模式學習2 裝飾者模式 head first 設計模式3 工廠模式 head first設計模式4 命令模式 head first 設計模式5 介面卡模式和外觀模式 head...