設計模式之單例模式

2021-08-01 03:03:49 字數 3163 閱讀 8139

什麼時候採用單例模式:

當某個類只需要乙個例項的時候,比如一台電腦 可以連線多個印表機,但是乙個時間段只能有乙個列印服務。

單例模式保證乙個類僅有乙個例項,並提供乙個訪問它的全域性訪問點。

通常我們可以讓乙個全域性變數使得乙個物件被訪問,但它不能防止你例項化多個物件。乙個最好的辦法就是,讓類自身負責儲存它的唯一例項。這個類可以保證沒有其他例項可以被建立,並且他可以提供乙個訪問該例項的辦法。

-:表示private   +:表示public

1. 單例類(此處的單例類是懶漢式單例類,其處理方式是在第一次被引用時,才會將自己例項化,所以被稱為懶漢式單例類)

public class singleton 

//此方法是獲得本類例項的唯一全域性訪問點

public static singleton getinstance()

return instance;

}}

客戶端**:

public class main 

else

system.out.println("兩個物件不是相同的例項");

}}

執行結果:

說明:單例模式保證了唯一的例項。

2. 多執行緒時的單例

認真思考會發現,上面的例子存在問題,比如,在多執行緒的程式中,多個執行緒同時訪問singleton類,呼叫getinstance()方法,會有可能造成建立多個例項。

解決辦法:加鎖,在getinstance 方法上加上synchronized 。所有這個類的加了 synchronized 的方法,在執行時,會獲得乙個該類的唯一的同步鎖,當這個鎖被占用時,其他的加了 synchronized 的方法就必須等待

public static synchronized singleton getinstance()

return instance;

}

這段**使得物件例項由最先進入的那個執行緒建立,以後的執行緒在進入時不會再去建立物件例項。這就保證了多執行緒環境下的同時訪問也不會造成多個例項的生成。

但是它仍然存在問題:每次呼叫getinstance 方法都會加鎖,這樣會影響效能。同步方法是對方法的整體進行加鎖,對執行效率來講很不利,因此考慮採用同步**塊。

改進辦法:雙重鎖定

3.雙重鎖定

雙重鎖定:不用讓執行緒每次都加鎖,而是在例項被建立的時候再加鎖處理。同時也保證了多執行緒的安全。這種做法被稱為double-check locking (雙重鎖定)

public static singleton getinstance()

}} return instance;

}

那為什麼上面在同步裡面還要做一次instance例項是否存在的判斷呢?

因為當instance為null時,並且存在同時有兩個執行緒呼叫getinstance 方法時,它都將可以通過第一重instance的判斷,然後由於同步機制,這兩個執行緒只有乙個可以進入,另乙個在外排隊等候,必須要其中乙個進入並出來後,另乙個才能進入。而此時如果沒有第二重的instance是否為null的判斷,則第乙個執行緒建立了例項,而第二個執行緒還是可以繼續建立新的例項,這就沒有達到單例的目的。

但是上面這邊方法仍然存在問題。原因在於sinstance =new singleton();這句話建立了乙個物件,可以分解成為3個步驟:

(1)分配物件的記憶體空間

(2)初始化物件

(3)設定sinstance指向剛分配的記憶體位址

其中,(2)和(3)之間可能會發生重排序,這種重排序可能會導致執行緒b訪問到的是乙個還未初始化的物件。

因此需要將物件宣告為volatitle,前面的重排序在多執行緒環境中將會被禁止

public class singleton 

public static singleton getinstance() }}

return instance;}}

4.餓漢式單例類

餓漢式單例類:採用以下靜態初始化方式在自己被載入時就將自己例項化,所以被形象地稱為餓漢式單例類

public class singleton2 

//此方法是獲得本類例項的唯一全域性訪問點

public static singleton2 getinstance()

}

5.靜態內部類實現單例模式

懶漢模式考慮執行緒安全需要在獲取單例的方法新增synchronized關鍵字實現同步**塊,這樣造成了效能損耗;而餓漢模式不能延遲例項化物件,下面是乙個靜態內部類單例模式的實現,既保證了執行緒的安全,有能夠延遲載入,也就是在第一次使用的時候載入。

靜態內部類不會隨著外部類的初始化而初始化,他是要單獨去載入和初始化的,當第一次執行getinstance方法時,inner類會被初始化。靜態物件instance的初始化在singleton3handler類初始化階段進行,類初始化階段即虛擬機器執行類構造器()方法的過程。虛擬機會保證乙個類的()方法在多執行緒環境下被正確的加鎖和同步,如果多個執行緒同時初始化乙個類,只會有乙個執行緒執行這個類的()方法,其它執行緒都會阻塞等待。

public class singleton3 

public static singleton3 getinstance()

private static class singleton3handler

}

6.三者對比

1.由於餓漢式,即靜態初始化的方式,它是類一載入就例項化的物件,所以要提前占用系統資源。

2.懶漢式會面臨多執行緒訪問的安全性問題,需要做雙重鎖定這樣的處理才可以保證安全。

3.靜態內部類單例模式的實現,既保證了執行緒的安全,有能夠延遲載入

4.到底使用哪一種方式,取決於實際的需求。

測試**:

public class mythread extends thread

@override

public void run()

}}

設計模式之單例模式

前一段時間買了一本秦小波寫的 設計模式之禪 網上對這書的評價很高。現在還沒有看很多,但是有些地方頗有感觸,也並不是所有的地方都能看懂,但是會慢慢研究的。自己對於設計模式的感覺就是乙個字 牛!感覺會23種設計模式並且會熟練運用的人,真的就是大師級的牛人了,設計模式是乙個專案主管或者架構師一定要會的東西...

設計模式之單例模式

package com.xie.singleton public class singleton 提供乙個共有的靜態的入口方法 public static singleton getinstance 懶漢式 延遲載入 提供乙個私有的靜態的成員變數,但不做初始化 private static sing...

設計模式之 單例模式

單例模式 singleton 保證乙個類僅有乙個例項,並提供乙個訪問它的全域性訪問點。單例模式 單件模式 使用方法返回唯一的例項 public class singleton private static singleton instance public static singleton geti...