单例双重加锁
相信面向?qū)ο蟪绦騿T都對(duì)單例模式比較熟悉,而對(duì)于單例模式卻有著各種各樣的寫法,今天我專門針對(duì)一種稱為雙重加鎖的寫法進(jìn)行分析。我們先來(lái)看下這種寫法。
/*** 單例雙重加鎖Demo**/ public class DoubleCheckLock {private static DoubleCheckLock instance ;private DoubleCheckLock(){}public static DoubleCheckLock getInstance(){if(instance == null){synchronized (DoubleCheckLock.class) {if(instance == null)instance = new DoubleCheckLock() ;}}return instance;} }這種寫法相信很多人都見(jiàn)過(guò),但是你認(rèn)為這種寫法是正確的嗎?或者更準(zhǔn)確的來(lái)說(shuō),這種寫法在并發(fā)的環(huán)境下是否還能表現(xiàn)出正確的行為呢。
之所以有這種所謂的雙重加鎖,一方面是因?yàn)檠舆t初始化可以提高性能,另一方面通過(guò)使用內(nèi)置鎖sychronized來(lái)防止并發(fā),其原理是首先檢查是否在沒(méi)有同步的情況下進(jìn)行了初始化,如果沒(méi)有的話,在進(jìn)行同步,然后再次檢查是否對(duì)其(instance)進(jìn)行了初始化,如果沒(méi)有那么則初始化DoubleCheckLock。
這種寫法表面看起來(lái)既提高了性能,又保證了線程安全。但實(shí)際上卻并不是如此,我只從線程安全上來(lái)分析這種寫法的對(duì)錯(cuò)。
在這,首先應(yīng)該注意的是使用內(nèi)置鎖加鎖的是DoubleCheckLock.class,并不是instance,也就是說(shuō)沒(méi)有在instance實(shí)現(xiàn)同步,那么在這種情況下,當(dāng)有兩個(gè)線程同時(shí)進(jìn)行到synchronized代碼塊時(shí),只有一個(gè)線程可以進(jìn)入,然后初始化了instance,但是這僅僅只能保證的是兩個(gè)線程在訪問(wèn)上的獨(dú)占性,也就是說(shuō)兩個(gè)線程在此一定是一先一后進(jìn)行訪問(wèn),但是不能保證的是instance的內(nèi)存可見(jiàn)性,原因很簡(jiǎn)單,因?yàn)橥降膶?duì)象并不是instance,而是DoubleCheckLock.class(可以保證內(nèi)存可見(jiàn)性)。不能保證內(nèi)存可見(jiàn)性的后果就是當(dāng)?shù)谝粋€(gè)線程初始化instance之后,第二個(gè)線程并不能馬上看見(jiàn)instance被初始化,或者更準(zhǔn)確的來(lái)說(shuō),第二個(gè)線程看到的可能只是被部分構(gòu)造的instance。因此,這種造成的后果是第二個(gè)線程讀取到了錯(cuò)誤的instance的狀態(tài),有可能instance會(huì)被再次實(shí)例化。
那么如何解決這個(gè)問(wèn)題呢,最簡(jiǎn)單的方式是對(duì)instance加上關(guān)鍵詞volatile,volatile可以保證變量的內(nèi)存可見(jiàn)性,同時(shí)volatile同步的消耗也非常小,這么做到話,可以保證線程安全。
上述解決問(wèn)題的方式固然是可以,但是實(shí)質(zhì)上我感覺(jué)很繁瑣其代碼閱讀效果也不好,就單例而言,我推薦一下的寫法。
public class Single {private Single(){}private static class SingleHolder{public static Single instance = new Single();}public static Single getInstance(){return SingleHolder.instance;} }這種寫法相對(duì)而言比較簡(jiǎn)單,而且處理了兩個(gè)問(wèn)題:1.線程安全問(wèn)題。2.延遲初始化(初始化在調(diào)用getInstance的時(shí)候才會(huì)去靜態(tài)內(nèi)部類中初始化instance)。而且相對(duì)而言,有著更加良好的代碼可讀性。
對(duì)于雙重加鎖的這種寫法就先分析到這,等后面說(shuō)到Happens-Before之后我會(huì)再來(lái)分下下雙重加鎖。
?
轉(zhuǎn)載于:https://www.cnblogs.com/yanfengfree/p/6271359.html
總結(jié)
- 上一篇: 前端工具网站推荐
- 下一篇: 做了一个网页,顺便录制了一个视频,大家看