爲何要用單例,你真的會寫單例模式嗎

優秀的設計結構能夠規避不少潛在的性能問題,對系統性能的影響可能遠遠大於代碼的優化,因此咱們須要知道一些設計模式和方法。設計模式

單例模式:多線程

單例模式是一種對象建立模式,用於生產一個對象的實例,它能夠確保系統中一個類只產生一個實例,這樣作有兩個好處:函數

1.對於頻繁使用的對象,能夠省略建立對象所花費的時間,這對於那些重量級對象而言,是很是可觀的一筆系統開銷。性能

2.因爲new操做的次數減小,因此係統內存的使用評率也會下降,這將減小GC壓力,縮短GC停頓時間。優化

因爲以上兩點可知單例模式的使用對於系統的關鍵組件和頻繁使用的對象來講是能夠有效的改善系統的性能的。線程

單例的核心是經過一個方法返回惟一的一個對象實例,首先單例類必須有一個private訪問級別的構造函數,由於,只有這樣,才能保證單例不會再系統中的其餘代碼內被實例化,其次,instance成員變量和getInstance方法必須是static的。設計

須要對instance實例作延遲加載對象

假如單例的建立過程很慢(構造方法中有其餘耗時操做),而且不是延遲加載的(因爲instance成員變量是static定義的,所以在JVM加載單例類時,單例對象就會被建立),若是此時這個單例類還在系統中扮演着其餘角色(單例類還有其餘非建立單例的靜態方法),那麼在任何使用這個單例類的地方都會初始化這個單例變量,而無論是否會被用到。也就是說雖然並無使用單例類,可是它仍是被建立出來了,這是咱們不肯意看到的,爲了解決這個問題,就須要引入延遲加載機制。內存

對於靜態變量instance初始值賦null,確保系統啓動時沒有額外的負載,在getInstance()工廠方法中,判斷當前單例是否已存在,若存在則返回,若不存在則建立單例,同時getInstance()方法應該是同步的。get

爲了延遲加載而引入同步關鍵字會下降系統性能,爲了解決這個問題,可使用內部類來維護單例的實例,當單例類被加載時,其內部類並不會被初始化,因此能夠確保單例類被加載進入JVM時,不會初始化單例類,而當getInstance方法被調用時纔會加載SingletonHolder從而初始化instance,因爲實例的創建是在類加載時完成,故天生對多線程友好,getInstance方法也不須要使用同步關鍵字,因此這種方法兼容上邊說的兩種實現的優勢。

一般狀況下,以上方式實現的單例已經能夠確保在系統中中存在惟一的實例了,可是也有例外的狀況致使系統生成多個實例,好比,在代碼中經過反射機制強行調用單例類的私有構造函數來生成多個單例。針對這種極端的狀況也有克服的辦法,具體辦法請參考筆者頭條號中講解單例模式的其餘兩篇文章。

相關文章
相關標籤/搜索