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