摘要:簡(jiǎn)介最基本的實(shí)例中規(guī)定了一個(gè)類只會(huì)被初始化一次所以該方法是線程安全的但是其在方法調(diào)用前就初始化了比較浪費(fèi)資源優(yōu)點(diǎn)只有一個(gè)實(shí)例節(jié)約內(nèi)存空間減少了系統(tǒng)的性能開銷如果某一個(gè)對(duì)象的產(chǎn)生需要比較多的資源時(shí)可以在啟動(dòng)時(shí)直接產(chǎn)生一個(gè)單例對(duì)象使其永駐內(nèi)存可
In software engineering, the singleton pattern is a software design pattern that restricts the instantiation of a class to one object. This is useful when exactly one object is needed to coordinate actions across the system. The concept is sometimes generalized to systems that operate more efficiently when only one object exists, or that restrict the instantiation to a certain number of objects. The term comes from the mathematical concept of a singleton簡(jiǎn)介 最基本的實(shí)例
public class Emperor { private static final Emperor emperor=new Emperor(); private Emperor(){} public static Emperor getInstance(){ return emperor; } }
Java Language Specification 中規(guī)定了一個(gè)類只會(huì)被初始化一次.所以該方法是線程安全的, 但是其在方法調(diào)用前就初始化了, 比較浪費(fèi)資源.
優(yōu)點(diǎn)只有一個(gè)實(shí)例, 節(jié)約內(nèi)存空間, 減少了系統(tǒng)的性能開銷, 如果某一個(gè)對(duì)象的產(chǎn)生需要比較多的資源時(shí), 可以在啟動(dòng)時(shí)直接產(chǎn)生一個(gè)單例對(duì)象, 使其永駐內(nèi)存.
可以避免對(duì)資源的多重占用,
可以在系統(tǒng)設(shè)置全局的訪問(wèn)點(diǎn), 優(yōu)化和共享資源訪問(wèn).
缺點(diǎn)單例模式一般沒(méi)有接口, 擴(kuò)展很困難, 除了修改代碼基本上沒(méi)有第二種途徑可以實(shí)現(xiàn)
單例模式不利于測(cè)試, 如果單例模式?jīng)]有完成, 無(wú)法進(jìn)行測(cè)試
與單一職責(zé)原則相沖突.
其它實(shí)現(xiàn)方式 懶漢模式class Singleton { private static Singleton instance; private Singleton(){} public static synchronized Singleton getInstance(){ if(instance==null){ instance=new Singleton(); } return instance; } }
該實(shí)現(xiàn)只會(huì)在需要的時(shí)候才會(huì)進(jìn)行初始化且是線程安全的, 但是每次調(diào)用getInstance()都會(huì)進(jìn)行同步, 會(huì)浪費(fèi)資源
Double Check Lockclass SingletonDCL{ private static SingletonDCL sInstance; private SingletonDCL(){} public static SingletonDCL getInstance(){ if(sInstance==null){ synchronized (SingletonDCL.class){ if(sInstance==null){ sInstance=new SingletonDCL(); } } } return sInstance; } }
該實(shí)現(xiàn)只會(huì)在需要的時(shí)候才會(huì)進(jìn)行初始化, 看似線程安全, 但實(shí)際并不是.
假設(shè)線程A執(zhí)行到sInstance=new SingletonDCL(), 這句代碼并不是一個(gè)原子操作, 這句代碼大致會(huì)被分為下面3個(gè)步驟來(lái)處理:
給SingletonDCL的實(shí)例分配內(nèi)存
調(diào)用SingletonDCL的構(gòu)造函數(shù), 初始化成員字段
將sInstance對(duì)象指向分配的內(nèi)存空間 (此時(shí)sInstance就不是null了).
如果這句代碼嚴(yán)格按照這個(gè)順序執(zhí)行,該DCL單例模式便是線程安全的, 但是事實(shí)并非如此. 原因是JVM并沒(méi)有保證上述第2和第3步的執(zhí)行順序.
也就是說(shuō)執(zhí)行步驟可能是1-3-2, 這種執(zhí)行步驟就會(huì)出問(wèn)題:
當(dāng)先執(zhí)行第3步時(shí), 另一個(gè)線程B開始執(zhí)行getInstance(), 由于此時(shí)sInstance已經(jīng)不是null了, 所以線程B會(huì)返回一個(gè)還未初始化的sInstance, 出現(xiàn)了錯(cuò)誤.
JVM1.5之后改善了這個(gè)問(wèn)題, 在sInstance前加上volatile關(guān)鍵字可以確保線程安全.
即private static volatile SingletonDCL sInstance;
DCL單例模式并不推薦使用,《Java并發(fā)編程實(shí)踐》推薦使用下面這個(gè)方法:
class SingletonStatic{ private SingletonStatic(){} public static SingletonStatic getInstance(){ return SingletonStaticHolder.sInstance; } private static class SingletonStaticHolder{ private static final SingletonStatic sInstance=new SingletonStatic(); } }
第一次加載時(shí), 并不會(huì)初始化sInstance, 只在第一調(diào)用getInstance()時(shí)初始化, 且該方法是線程安全的.
枚舉單例enum SingletonEnum{ INSTACNE; public void doSomething(){ StdOut.println("doSomething..."); } }
枚舉單例模式有以下3個(gè)優(yōu)點(diǎn):
線程安全, 任何時(shí)候都只有一個(gè)實(shí)例
反序列化時(shí), 都只會(huì)有一個(gè)實(shí)例
可以防止反射攻擊
選擇哪一種實(shí)現(xiàn)方式無(wú)論采用哪一種實(shí)現(xiàn)方式, 都要確保線程安全, 防止反序列化導(dǎo)致重新生成實(shí)例對(duì)象等一些問(wèn)題. 具體選擇哪一種實(shí)現(xiàn)方式取決于項(xiàng)目本身.
關(guān)于序列化除了枚舉單例, 為了避免單例對(duì)象在被反序列化時(shí)重新生成對(duì)象, 必須加入以下方法
private Object readResolve() throws ObjectStreamException{ return sInstance; }
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/71722.html
摘要:總結(jié)單例是運(yùn)用頻率很高的模式,因?yàn)榭蛻舳藳](méi)有高并發(fā)的情況,選擇哪種方式并不會(huì)有太大的影響,出于效率考慮,推薦使用和靜態(tài)內(nèi)部類實(shí)現(xiàn)單例模式。 單例模式介紹 單例模式是應(yīng)用最廣的模式之一,也可能是很多人唯一會(huì)使用的設(shè)計(jì)模式。在應(yīng)用單例模式時(shí),單例對(duì)象的類必須保證只用一個(gè)實(shí)例存在。許多時(shí)候整個(gè)系統(tǒng)只需要一個(gè)全局對(duì)象,這樣有利于我么能協(xié)調(diào)整個(gè)系統(tǒng)整體的行為。 單例模式的使用場(chǎng)景 確保某個(gè)類有且...
摘要:不符合設(shè)計(jì)模式中的單一職責(zé)的概念。引入代理實(shí)現(xiàn)單例模式引入代理實(shí)現(xiàn)單例模式的特點(diǎn)我們負(fù)責(zé)管理單例的邏輯移到了代理類中。的單例模式對(duì)比在以上的代碼中實(shí)現(xiàn)的單例模式都混入了傳統(tǒng)面向?qū)ο笳Z(yǔ)言的特點(diǎn)。 聲明:這個(gè)系列為閱讀《JavaScript設(shè)計(jì)模式與開發(fā)實(shí)踐》 ----曾探@著一書的讀書筆記 1.單例模式的特點(diǎn)和定義 保證一個(gè)類僅有一個(gè)實(shí)例,并且提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。 2.傳統(tǒng)面向?qū)?..
摘要:但是,這并不是采用單例的唯一原因。使用命名空間單例模式也被稱為模塊設(shè)計(jì)模式。函數(shù)內(nèi)部聲明了一些局部函數(shù)和或變量。緊隨函數(shù)聲明放置即可立即執(zhí)行外部函數(shù),并將所得的對(duì)象文字費(fèi)賠給變量。 JavaScript設(shè)計(jì)模式-第一部分:?jiǎn)卫J?、組合模式和外觀模式 設(shè)計(jì)模式是一些可靠的編程方式,有助于保證代碼更加易于維護(hù)、擴(kuò)展及分離,所有設(shè)計(jì)模式在創(chuàng)建大型JavaScript應(yīng)用程序時(shí)均不可或缺 單...
摘要:如果需要防范這種攻擊,請(qǐng)修改構(gòu)造函數(shù),使其在被要求創(chuàng)建第二個(gè)實(shí)例時(shí)拋出異常。單例模式與單一職責(zé)原則有沖突。源碼地址參考文獻(xiàn)設(shè)計(jì)模式之禪 定義 單例模式是一個(gè)比較簡(jiǎn)單的模式,其定義如下: 保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問(wèn)它的全局訪問(wèn)點(diǎn)。 或者 Ensure a class has only one instance, and provide a global point of ac...
摘要:在設(shè)計(jì)模式一書中,將單例模式稱作單件模式。通過(guò)關(guān)鍵字,來(lái)保證不會(huì)同時(shí)有兩個(gè)線程進(jìn)入該方法的實(shí)例對(duì)象改善多線程問(wèn)題為了符合大多數(shù)程序,很明顯地,我們需要確保單例模式能在多線程的情況下正常工作。 在《Head First 設(shè)計(jì)模式》一書中,將單例模式稱作單件模式。這里為了適應(yīng)大環(huán)境,把它稱之為大家更熟悉的單例模式。 一、了解單例模式 1.1 什么是單例模式 單例模式確保一個(gè)類只有一個(gè)實(shí)例,...
閱讀 2637·2021-11-23 09:51
閱讀 3169·2019-08-30 15:54
閱讀 1129·2019-08-30 14:14
閱讀 3599·2019-08-30 13:59
閱讀 1509·2019-08-29 17:09
閱讀 1535·2019-08-29 16:24
閱讀 2903·2019-08-29 15:43
閱讀 985·2019-08-29 12:45