設計模式三 單例設計模式

2021-08-09 02:40:39 字數 2776 閱讀 2232

引言:單例設計模式是我們設計模式學習中很重要的乙個,在實際開發中用處也非常多,今天把單利設計模式詳細的總結一下,大家一起交流分享一下。

定義:單例設計模式就是保證乙個類僅有乙個例項,並提供乙個訪問他的全域性訪問點。

用處:有時候對於系統過來說乙個例項很重要,例如:乙個系統可以有多個列印任務,但是只能有乙個正在工作的任務,乙個系統只能有乙個視窗管理器或者檔案系統;乙個系統只能開啟乙個任務管理器,如果不使用單利機制對視窗物件唯一化,將彈出多個視窗,如果這些視窗的像是內容完全一樣,則是重複的,浪費資源,如果這些視窗內容不一致,則意味著某一瞬間系統有多個狀態,與實際不符,也給使用者**誤解,不知道哪乙個才是真實的狀態,因此有時確保系統中某個物件的唯一性非常重要。

那麼如何保證乙個例項並且這個例項易於被訪問呢?

思路:1.我們知道乙個類通常都是根據建構函式來例項化的,那麼假如將這個類的建構函式給私有化了,就不能直接new這個類,來建立物件了,後續具體如何操作全都放在這個類中,我們只負責呼叫其具體例項就好。

2.那麼如何提供乙個全域性的訪問點呢?我們知道static關鍵字的作用,如果把某一欄位設定為靜態的話,那麼全域性都可以訪問它,他在類載入的時候就已經存在了,正好適合我們。

下面我們寫出想像中的**:

package test0930;

public class singleton

//給出乙個公共的靜態方法返回乙個單一例項

public static singleton getinstance()

return singleton;

} }

好了,現在我們實現了單例類的編寫,可以總結為:

1.靜態例項,帶有static關鍵字的屬性在每乙個類中都是唯一的。

2.限制客戶端隨意創造例項,即私有化構造方法,此為保證單例的最重要的一步。

3.給乙個公共的獲取例項的靜態方法,注意,是靜態的方法,因為這個方法是在我們未獲取到例項的時候就要提供給客戶端呼叫的,所以如果是非靜態的話,那就變成乙個矛盾體了,因為非靜態的方法必須要擁有例項才可以呼叫。

4.判斷只有持有的靜態例項為null時才呼叫構造方法創造乙個例項,否則就直接返回。

優化:我們知道,如果想要對執行緒進行同步的話,一般可以踩用synchronized關鍵字,所以改進之後的**如下:

package test0930;

public class singletondouble

//給出乙個公共的靜態方法返回乙個單一例項

public static singletondouble getinstance()

}}

return singleton;

} }

改進之後,引入了同步**塊,對singletondouble 類進行同步,這樣同步之後,只能有乙個執行緒進入同步塊,其他執行緒只能排隊等待,避免了沒有同步時候執行緒搶占造成的建立多個例項。

這裡的兩個判斷主要用處:外層的if主要是在同步塊之前判斷,如果不為空,那麼完全沒必要進入同步塊,避免了浪費是資源,如果為空,說明當前時候例項為空,這時會涉及到多執行緒的問題,第二個if就是為了解決這個問題的。

經過剛才的分析,貌似上述雙重加鎖的示例看起來是沒有問題了,但如果再進一步深入考慮的話,其實仍然是有問題的。如果我們深入到jvm中去探索上面這段**,它就有可能(注意,只是有可能)是有問題的, 因為虛擬機器在執行建立例項的這一步操作的時候,其實是分了好幾步去進行的,也就是說建立乙個新的物件並非是原子性操作。在有些jvm中上述做法是沒有問題的,但是有些情況下是會造成莫名的錯誤。

首先要明白在jvm建立新的物件時,主要要經過三步:

1.分配記憶體

2.初始化構造器

3.將物件指向分配的記憶體位址

如果是按照上面的三步一次執行,那麼是沒有問題的,因為jvm是將構造完的完整的物件分配了記憶體的位址,但是如果2和3步反了就會出現問題了(那麼2和3步真的會反了麼?會的,因為jvm會對位元組碼進行調優,其中一項調優就是指令順序調優,那麼2和3順序就有可能相反,先執行3後執行2),此時如果執行緒a執行完了3,但是沒有執行2步就退出了同步塊,這時執行緒b進入同步塊,if判斷例項不為空(因為這時例項已經分配了記憶體空間,但是沒有賦值,執行緒b會認為例項已經存在,進而直接返回),直接返回,造成返回的是還沒有賦值的例項,會造成未知的錯誤,這個問題在jdk1.5之後就得到了解決,就是volatile關鍵字,他的主要是作用是防止指令重排,如果用這個關鍵字修飾例項物件的話,就可以避免上述錯誤。

第一種:private static volatile singletondouble singleton; //就是在這裡加乙個關鍵字,其他不變,起到防止指令重排的作用

第二種(更好用的單例模式):

package test0930;

public class singletoninnerclass

// 給出乙個公共的靜態方法返回乙個單一例項

public static singletoninnerclass getinstance()

// 乙個靜態內部類

private static class singleton

}

這種方法利用靜態內部類,來初始化例項物件,避免了多執行緒導致的併發,因為乙個類的靜態成員,實在類的初始化的時候就已經建立好的,並且jvm會自動同步這個初始化過程,不會在初始化過程中其他執行緒搶占的情況,也由於只初始化一次,那麼就是單例的。通常單例通常就是最後兩種,其中最後一種更加簡潔一點,建議後一種。

設計模式三 單例模式

單例模式也是建立型模式的一種,也是23種設計模式中比較簡單的一種。見名思意,在整個軟體系統中,只有某個型別的乙個物件,並且訪問他的地方也只有乙個,也就是只有乙個全域性物件訪問點,這個例項或物件被所有是應用程式所共享 很多可以使用到這樣的功能模組 比如資料庫連線池物件 印表機物件,因為整個系統中,資料...

設計模式 三 單例模式

package zzq.designpatterns.creativepattern import lombok.data 單例 singleton 模式的定義 指乙個類只有乙個例項,且該類能自行建立這個例項的一種模式。例如,windows 中只能開啟乙個任務管理器,這樣可以避免因開啟多個任務管理器...

設計模式 單例設計模式

歷史 最早是建築學領域的模式,然後gof四人由其引申到編碼方面,總結了23種設計模式 設計模式 解決某一類事情最行之有效的方法 2.1 體現 餓漢式,保證物件的唯一性 class singleton 私有化建構函式禁止該類建立物件 private static singleton st new si...