阿里面試官:如何實(shí)現(xiàn)一個(gè)線程安全的單例,前提是不能加鎖

單例,大家肯定都不陌生,這是Java中很重要的一個(gè)設(shè)計(jì)模式。稍微了解一點(diǎn)單例的朋友也都知道實(shí)現(xiàn)單例是要考慮并發(fā)問題的,一般情況下,我們都會(huì)使用synchronized來保證線程安全。

那么,如果有這樣一道面試題:不使用synchronized和lock,如何實(shí)現(xiàn)一個(gè)線程安全的單例?你該如何回答?

C類應(yīng)聘者:可以使用餓漢模式實(shí)現(xiàn)單例。如:

public class Singleton {

? ? private static Singleton instance = new Singleton();

? ? private Singleton (){}

? ? public static Singleton getInstance() {

? ? ? return instance;

? ? }

}

還有部分程序員可以想到餓漢的變種:

public class Singleton {

? ? private Singleton instance = null;

? ? static {

instance = new Singleton();

? ? }

? ? private Singleton (){}

? ? public static Singleton getInstance() {

? ? ? ? return this.instance;

? ? }

}

使用static來定義靜態(tài)成員變量或靜態(tài)代碼,借助Class的類加載機(jī)制實(shí)現(xiàn)線程安全單例。

面試官:除了這種以外,還有其他方式嗎?

B類應(yīng)聘者:

除了以上兩種方式,還有一種辦法,就是通過靜態(tài)內(nèi)部類來實(shí)現(xiàn),代碼如下:

public class Singleton {

? ? private static class SingletonHolder {

? ? private static final Singleton INSTANCE = new Singleton();

}

private Singleton (){}

public static final Singleton getInstance() {

return SingletonHolder.INSTANCE;

}

}

這種方式相比前面兩種有所優(yōu)化,就是使用了lazy-loading。Singleton類被裝載了,但是instance并沒有立即初始化。因?yàn)镾ingletonHolder類沒有被主動(dòng)使用,只有顯示通過調(diào)用getInstance方法時(shí),才會(huì)顯示裝載SingletonHolder類,從而實(shí)例化instance。

面試官:除了這種以外,還有其他方式嗎?

A類應(yīng)聘者:

除了以上方式,還可以使用枚舉的方式,如:

public enum Singleton {

INSTANCE;

? ? public void whateverMethod() {

}

}

這種方式是Effective Java作者Josh Bloch 提倡的方式,它不僅能避免多線程同步問題,而且還能防止反序列化重新創(chuàng)建新的對(duì)象,可謂是很堅(jiān)強(qiáng)的壁壘。

面試官:以上幾種答案,其實(shí)現(xiàn)原理都是利用借助了類加載的時(shí)候初始化單例。即借助了ClassLoader的線程安全機(jī)制。

所謂ClassLoader的線程安全機(jī)制,就是ClassLoader的loadClass方法在加載類的時(shí)候使用了synchronized關(guān)鍵字。也正是因?yàn)檫@樣, 除非被重寫,這個(gè)方法默認(rèn)在整個(gè)裝載過程中都是同步的,也就是保證了線程安全。

所以,以上各種方法,雖然并沒有顯示的使用synchronized,但是還是其底層實(shí)現(xiàn)原理還是用到了synchronized。

面試官:除了這種以外,還有其他方式嗎?

A類應(yīng)聘者:

還可以使用Java并發(fā)包中的Lock實(shí)現(xiàn)

面試官:本質(zhì)上還是在使用鎖,不使用鎖的話,有辦法實(shí)現(xiàn)線程安全的單例嗎?

A+類面試者:

有的,那就是使用CAS。

CAS是項(xiàng)樂觀鎖技術(shù),當(dāng)多個(gè)線程嘗試使用CAS同時(shí)更新同一個(gè)變量時(shí),只有其中一個(gè)線程能更新變量的值,而其它線程都失敗,失敗的線程并不會(huì)被掛起,而是被告知這次競(jìng)爭(zhēng)中失敗,并可以再次嘗試。實(shí)現(xiàn)單例的方式如下:

public class Singleton {

? ? private static final AtomicReference INSTANCE = new AtomicReference();

? ? private Singleton() {}

? ? public static Singleton getInstance() {

? ? ? ? for (;;) {

Singleton singleton = INSTANCE.get();

? ? ? ? ? ? if (null != singleton) {

? ? ? ? ? ? ? ? return singleton;

? ? ? ? ? ? }

singleton = new Singleton();

? ? ? ? ? ? if (INSTANCE.compareAndSet(null, singleton)) {

? ? ? ? ? ? ? ? return singleton;

? ? ? ? ? ? }

? ? ? ? }

? ? }

}

面試官:這種方式實(shí)現(xiàn)的單例有啥優(yōu)缺點(diǎn)嗎?

A++類面試者:

用CAS的好處在于不需要使用傳統(tǒng)的鎖機(jī)制來保證線程安全,CAS是一種基于忙等待的算法,依賴底層硬件的實(shí)現(xiàn),相對(duì)于鎖它沒有線程切換和阻塞的額外消耗,可以支持較大的并行度。

CAS的一個(gè)重要缺點(diǎn)在于如果忙等待一直執(zhí)行不成功(一直在死循環(huán)中),會(huì)對(duì)CPU造成較大的執(zhí)行開銷。

另外,如果N個(gè)線程同時(shí)執(zhí)行到singleton = new Singleton();的時(shí)候,會(huì)有大量對(duì)象創(chuàng)建,很可能導(dǎo)致內(nèi)存溢出。

面試官:你被錄取了!

------END

最后附上筆者創(chuàng)建的一個(gè)java技術(shù)交流群,歡迎大家進(jìn)群交流java相關(guān)的技術(shù),群主會(huì)不定時(shí)發(fā)紅包,組織抽獎(jiǎng),獎(jiǎng)品是下面幾本書之一:

從paxos到zookeeper分布式一致性原理與實(shí)踐? ? 作者:倪超

Redis設(shè)計(jì)與實(shí)現(xiàn)? ? 作者:黃建宏

kafka源碼分析? ?

分布式系統(tǒng)架構(gòu)設(shè)計(jì)與實(shí)現(xiàn)

高性能mysql

Innodb引擎原理分析

還有幾本,篇幅限制就不一一列舉了

作者精心創(chuàng)作整理的技術(shù)資料論壇

掃碼加群,享受美團(tuán),阿里,頭條內(nèi)推福利

注意:想去其他互聯(lián)網(wǎng)大廠的勿擾,目前只有美團(tuán),阿里,頭條的內(nèi)推通道

![image.png](https://upload-images.jianshu.io/upload_images/5931028-fc758cace9fd74cc.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,412評(píng)論 6 532
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,514評(píng)論 3 416
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,373評(píng)論 0 374
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,975評(píng)論 1 312
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 71,743評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,199評(píng)論 1 324
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,262評(píng)論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,414評(píng)論 0 288
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,951評(píng)論 1 336
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 40,780評(píng)論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 42,983評(píng)論 1 369
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,527評(píng)論 5 359
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,218評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,649評(píng)論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,889評(píng)論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,673評(píng)論 3 391
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 47,967評(píng)論 2 374

推薦閱讀更多精彩內(nèi)容

  • 下面最近發(fā)的一些并發(fā)編程的文章匯總,通過閱讀這些文章大家再看大廠面試中的并發(fā)編程問題就沒有那么頭疼了。今天給大家總...
    架構(gòu)師springboot閱讀 688評(píng)論 0 3
  • 本系列出于AWeiLoveAndroid的分享,在此感謝,再結(jié)合自身經(jīng)驗(yàn)查漏補(bǔ)缺,完善答案。以成系統(tǒng)。 Java基...
    濟(jì)公大將閱讀 1,535評(píng)論 1 6
  • 單例模式 單例模式(Singleton Pattern)是 Java 中最簡(jiǎn)單的設(shè)計(jì)模式之一。這種類型的設(shè)計(jì)模式屬...
    超級(jí)小學(xué)生1閱讀 352評(píng)論 0 0
  • 文/冰雪伊人 —詞曲系列— 山黛遠(yuǎn),微雨乍氤氳。十里蓮開香淡淡,幾橋風(fēng)起水粼粼?吹我綠羅裙。 韻:詞林,第六部(平...
    西域冰雪閱讀 1,546評(píng)論 9 16
  • 內(nèi)心的脆弱,容易成為他人砧板上的魚肉,趁此困境,好自反省。 佛說:他是來渡你的。以前非常排斥,但現(xiàn)在可...
    清淺隨性閱讀 464評(píng)論 0 0