這篇文章主要為大家詳細(xì)介紹了實現(xiàn)singleton的四種方法,文中示例代碼介紹的非常詳細(xì),零基礎(chǔ)也能參考此文章,感興趣的小伙伴們可以參考一下。

消耗內(nèi)存最嚴(yán)重的對象創(chuàng)建過程,必須對其進(jìn)行約束,作為創(chuàng)建型模式的單例模式(Singleton),始終保持應(yīng)用程序中某一個實例有且僅有一個,可以很顯著的提升程序性能。
單線程下的Singleton的穩(wěn)定性是極好的,可分為兩大類:
1.Eager(餓漢型): 類加載時立即創(chuàng)建對象。
public class EagerSingleton {
//1. 類加載時就立即產(chǎn)生實例對象,通過設(shè)置靜態(tài)變量被外界獲取
//2. 并使用private保證封裝安全性
private static EagerSingleton eagerSingleton = new EagerSingleton();
//3. 通過構(gòu)造方法的私有化,不允許外部直接創(chuàng)建對象,確保單例的安全性
private EagerSingleton(){
}
public static EagerSingleton getEagerSingleton(){
return eagerSingleton;
}2.Lazy(懶漢型):類加載時沒有立即創(chuàng)建對象,等到第一個用戶獲取才進(jìn)行實例化。
public class LazySingleton {
//1. 類加載時并沒有創(chuàng)建唯一實例
private static LazySingleton lazySingleton;
private LazySingleton() {
}
//2、提供一個獲取實例的靜態(tài)方法
public static LazySingleton getLazySingleton() {
if (lazySingleton == null) {
lazySingleton = new LazySingleton();
}
return lazySingleton;
}就性能方面而言,LazySingleton 明顯優(yōu)于 EagerSingleton ,若類的加載需要耗費大量的資源(e.g. 讀取大文件信息),那么LazySingleton 的優(yōu)勢顯而易見。但通過閱讀代碼,很容易發(fā)現(xiàn)一個致命問題。多線程間如何保持安全性?
下面將對多線程并發(fā)問題進(jìn)行解析:
解決該問題的關(guān)鍵在于兩方面:1.同步; 2.性能;
如何解救呢?
作為一個java的開發(fā)者,對synchronized一定不陌生,提到多線程,大部分人想到的都是他(JDK6后,他的性能提升巨大,解決簡單并發(fā),非常適用)。
那就讓我們用synchronized來嘗試解決吧:
//由synchronized進(jìn)行同步加鎖
public synchronized static LazySingleton getLazySingleton() {
if (lazySingleton == null) {
lazySingleton = new LazySingleton();
}
return lazySingleton;
}如此同步問題看似解決,但是作為一個開發(fā)者,最重要的是性能的保障,使用synchronized有利有弊,由于加鎖操作,代碼段被加上悲觀鎖,只有等一個請求完成,下個請求才能進(jìn)入執(zhí)行。通常加上synchronized關(guān)鍵字的代碼片會比同等量級的代碼慢上幾倍,這是我們不愿見到的。那如何避免這一問題呢?在java對synchronized的定義里有這樣的建議:越遲使用synchronized,性能越優(yōu)(細(xì)化鎖)。
###### 2.因此,我們需要開始解決性能的問題了。按照synchronized優(yōu)化: ######
public class DoubleCheckLockSingleton {
//使用volatile保證每次取值不是從緩存中取,而是從真正對應(yīng)的內(nèi)存地址中取.(下文解釋)
private static volatile DoubleCheckLockSingleton doubleCheckLockSingleton;
private DoubleCheckLockSingleton(){
}
public static DoubleCheckLockSingleton getDoubleCheckLockSingleton(){
//配置雙重檢查鎖(下文解釋)
if(doubleCheckLockSingleton == null){
synchronized (DoubleCheckLockSingleton.class) {
if(doubleCheckLockSingleton == null){
doubleCheckLockSingleton = new DoubleCheckLockSingleton();
}
}
}
return doubleCheckLockSingleton;
}
}上述源碼就是經(jīng)典的volatile關(guān)鍵字(JDK1.5 后重生)+雙重檢查鎖(DoubleCheck),大程度的優(yōu)化了sychronized帶來的性能開銷。下面將為大家解釋volatile與DoubleCheck。
1.volatile
是在JDK1.5后才正式被實現(xiàn)使用的,之前的版本只是定義了該關(guān)鍵字,未有具體實現(xiàn)。若想理解volatile就必須對JVM自身的內(nèi)存管理有些許了解:
1.1 遵循著摩爾定律,內(nèi)存的讀寫速度已遠(yuǎn)不能滿足CPU,因此現(xiàn)代計算機(jī)引入了在CPU上添加高速緩存的機(jī)制,由緩存預(yù)讀取內(nèi)存的值,并暫存于緩存中,通過計算,再更新內(nèi)存中的相應(yīng)值。
**1.2** 而JVM模仿PC的這一做法,在內(nèi)存中劃分了自己的**工作內(nèi)存**,該部分內(nèi)存作用與高速緩存一致,很顯著的提高JVM工作效率,但凡事都有利有弊,這一做法也導(dǎo)致工作內(nèi)存與其他內(nèi)存通信時容易導(dǎo)致傳輸上的問題。volatile的一個功能就是強(qiáng)制的從內(nèi)存中讀取最新的值,避免緩存與內(nèi)存不一致的狀況。
1.3 volatile的另一個功能也是和JVM相關(guān),即JVM會通過自身的判斷,將源碼的執(zhí)行順序重排,保證指令流水線連貫性,以達(dá)到最優(yōu)的執(zhí)行方案。這種做法提高了性能,但對DoubleCheck卻會產(chǎn)生意想外的結(jié)果,兩線程可能互相干擾。而volatile提供了happens-before guarantee(寫優(yōu)先于讀),使對象不被干擾,保證安全的穩(wěn)定性。
2.DoubleCheck
這是現(xiàn)代編程的遺留,假設(shè)進(jìn)入同步塊之后,對象已被實例化,此時需再次進(jìn)行判斷。
當(dāng)然還有一種官方推薦的單例實現(xiàn)方法:
由于類的構(gòu)造在定義中已是原子性的,因此上述的各種問題都不會再產(chǎn)生,是一種很好的單例實現(xiàn)方式,推薦使用。
//使用內(nèi)部類進(jìn)行單例構(gòu)造
public class NestedClassSingleton {
private NestedClassSingleton(){
}
private static class SingletonHolder{
private static final NestedClassSingleton nestedClassSingleton = new NestedClassSingleton();
}
public static NestedClassSingleton getNestedClassSingleton(){
return SingletonHolder.nestedClassSingleton;
}
}看完上述內(nèi)容,你們掌握實現(xiàn)singleton的四種方法的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝各位的閱讀!
網(wǎng)站名稱:實現(xiàn)singleton的四種方法-創(chuàng)新互聯(lián)
文章鏈接:http://chinadenli.net/article20/hpjco.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站導(dǎo)航、面包屑導(dǎo)航、網(wǎng)站建設(shè)、手機(jī)網(wǎng)站建設(shè)、定制網(wǎng)站、云服務(wù)器
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容