摘要:一為什么需要單例模式可以保證一個類僅有一個實例,控制實例數(shù)目,節(jié)約系統(tǒng)的資源。代碼示例枚舉是否多線程安全是是否初始化是描述推薦使用對于枚舉類來說,每個對象都是被修飾的。在第二版的第條,推薦使用枚舉實現(xiàn)單例模式。
一、為什么需要單例模式?
可以保證一個類僅有一個實例,控制實例數(shù)目,節(jié)約系統(tǒng)的資源。比如:數(shù)據(jù)庫的連接池。一些資源管理器常被設(shè)計成單例模式
二、怎么使用
2.1 餓漢式
是否多線程安全:是
是否 Lazy 初始化:否
描述:
優(yōu)點:沒有加鎖,執(zhí)行效率提高
缺點:在某些情況下,不是因為調(diào)用getInstance而導(dǎo)致的類初始化的話,那么會存在浪費內(nèi)存的情況
該模式是基于classLoader機制避免多線程的問題,當(dāng)讀取類的靜態(tài)字段(類靜態(tài)常量不是)、調(diào)用類的靜態(tài)方法時(當(dāng)然還有很多情況會觸發(fā)類的初始化,更多細(xì)節(jié)參考深入理解JVM虛擬機)。會觸發(fā)類的初始化。當(dāng)進(jìn)行初始化時,JVM會為類的靜態(tài)語句塊和為類變量賦值操作,生成
備注:有人說在類加載時就會初始化,浪費內(nèi)存,個人感覺是不對的。首先JVM的類加載會進(jìn)行類的加載(加載class文件),驗證(驗證字節(jié)碼文件),準(zhǔn)備(為類變量分配內(nèi)存并賦初值),解析(將符號引號轉(zhuǎn)為直接引用);緊接著再初始化,但是需要注意的是,已經(jīng)說明JVM什么時候才會為類進(jìn)行初始化。所以,說類在加載時就會初始化,個人感覺是不對的。如果個人講述錯誤,請留言
代碼示例:
public class Singleton { private static Singleton instance = new Singleton(); private Singleton (){} public static Singleton getInstance() { return instance; } }
2.2、靜態(tài)內(nèi)部類
是否多線程安全:是
是否 Lazy 初始化:是
代碼示例:
public class Singleton { private static class SingletonHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return SingletonHolder.INSTANCE; } }
2.3、雙檢鎖/雙重檢驗鎖(DCL,double checked locking)
是否多線程安全:是
是否 Lazy 初始化:是
描述:
缺點:實現(xiàn)復(fù)雜,且效率過低,每次都需要判斷一次if。不推薦使用
請注意
如果singleton變量沒有加上volatile,那么就是非線程安全的。來模擬一下:
線程A走到④處,初始化完畢了singleton,線程B走到②處。因為沒有加volatile,所以此時singleton可能不會對其他內(nèi)存立即可見,所以線程B也走到了④,因此,實例化了2個對象。
代碼示例:
public class Singleton { private volatile static Singleton singleton; private Singleton (){} public static Singleton getSingleton() { if (singleton == null) { ① synchronized (Singleton.class) { ② if (singleton == null) { ③ singleton = new Singleton(); ④ } } } return singleton; } }
2.4、枚舉
是否多線程安全:是
是否 Lazy 初始化:是
描述:推薦使用
對于枚舉類來說,每個對象(INSTANCE)都是被public static final修飾的。其次構(gòu)造函數(shù)默認(rèn)私有。所以用來實現(xiàn)單例模式,是非常適合的。
在Effective Java第二版的第77條,推薦使用枚舉實現(xiàn)單例模式。
代碼示例:
public enum Test{ INSTANCE; private Singleton singleton; Test() { singleton = new Singleton; } public Singleton getInstance() { return singleton; } }
有關(guān)參考:
java并發(fā)編程實戰(zhàn)
EffectiveJava 第二版
http://www.runoob.com/design-...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/67845.html
該文章屬于《編程中的那些經(jīng)典套路——設(shè)計模式匯總》系列,并且以下內(nèi)容基于語言PHP 在設(shè)計模式中,單例模式和工廠模式)可以說是使用的最普遍的設(shè)計模式了,所以掌握此種模式尤為重要。 單例模式一般使用在資源共享和需要控制資源的情況下。 例如:購物車,回收站,數(shù)據(jù)庫連接池,計數(shù)器,配置文件共享等所有項目中只需要存在一個的模塊,你都可以采用單例模式。 單例模式的好處就在于當(dāng)前進(jìn)程只產(chǎn)生一個對象(或者叫...
摘要:在寫單例模式的代碼之前,我們先簡單了解一下兩個知識點,關(guān)于類的加載順序和關(guān)鍵字。懶漢和餓漢在程序編寫上,一般將單例模式分為兩種,分別是餓漢式和懶漢式,餓漢式在類加載時就完成了初始化,所以類加載比較慢,但獲取對象的速度快。 定義 單例模式是比較常見的一種設(shè)計模式,目的是保證一個類只能有一個實例,而且自行實例化并向整個系統(tǒng)提供這個實例,避免頻繁創(chuàng)建對象,節(jié)約內(nèi)存。 單例模式的應(yīng)用場景很多, 比如...
摘要:枚舉單例以上是一個單例枚舉的例子,而我們要獲取該實例只需要,并且此種方式可以保證該單例線程安全防反射攻擊防止序列化生成新的實例。 關(guān)于單例模式,相信大家都所有了解,比較經(jīng)典的實現(xiàn)有餓漢式、借助內(nèi)部類、雙重鎖檢測,這些實現(xiàn)可以保證線程安全,但是在某些特殊情況下并不能夠保證僅僅只有一個單例,因為像序列化、反射攻擊等往往可以生成新的實例對象,本文將重點分析枚舉單例模式如何防止反射攻擊。 枚...
摘要:本篇文章總結(jié)了目前主流的實現(xiàn)單例模式的方法供讀者參考。使用實現(xiàn)單例模式同樣,我們在類的創(chuàng)建時進(jìn)行干預(yù),從而達(dá)到實現(xiàn)單例的目的。 很多初學(xué)者喜歡用 全局變量 ,因為這比函數(shù)的參數(shù)傳來傳去更容易讓人理解。確實在很多場景下用全局變量很方便。不過如果代碼規(guī)模增大,并且有多個文件的時候,全局變量就會變得比較混亂。你可能不知道在哪個文件中定義了相同類型甚至重名的全局變量,也不知道這個變量在程序的某...
閱讀 2680·2021-11-25 09:43
閱讀 2594·2021-11-22 09:34
閱讀 2863·2021-11-12 10:34
閱讀 1452·2021-10-20 13:46
閱讀 2310·2019-08-30 13:21
閱讀 940·2019-08-30 11:21
閱讀 494·2019-08-30 11:20
閱讀 2199·2019-08-29 17:20