摘要:把準(zhǔn)備過程紀(jì)錄下來,共勉。單例模式有幾種經(jīng)典寫法,核心思想就是將構(gòu)造函數(shù)私有化,并且通過靜態(tài)方法獲取一個(gè)唯一的實(shí)例。
寫在最前面
導(dǎo)師貪腐出逃美國,兩年未歸,可憐了我。拿了小米和美團(tuán)的offer,要被延期,offer失效,工作重新找。把準(zhǔn)備過程紀(jì)錄下來,共勉。
單例模式有幾種經(jīng)典寫法,核心思想:就是將構(gòu)造函數(shù)私有化,并且通過靜態(tài)方法獲取一個(gè)唯一的實(shí)例。
餓漢式public class Singleton{ private Singleton(){} private static Singleton instance = new Singleton(); public static Singleton getInstance(){ return instance; } }懶漢式
public class Singleton{ private Singleton(){} private static Singleton instance = null; public static Singleton getInstance(){ instance = new Singleton(); return instance; } }雙鎖式
public class Singleton{ private Singleton(){ } private volatile static Singleton instance = null; public static Singleton getInstance(){ if(instance == null){ synchonized(Singleton.class){ if(instance == null){ instance = new Singleton(); } } } return instance; } }
關(guān)于volatile關(guān)鍵字
上面添加了volatile關(guān)鍵字,如果沒有volatile關(guān)鍵字,在執(zhí)行instance = new Singleton()時(shí)可能會(huì)出現(xiàn)問題,偽代碼如下:
inst = allocat(); // 第一步:分配內(nèi)存 constructor(inst); // 第二步:執(zhí)行構(gòu)造函數(shù) instance = inst; // 第三步:賦值,將instance對(duì)象指向分配的內(nèi)存空間(此時(shí)instance就不是null了)
由于Java編譯器允許處理器亂序執(zhí)行,所以第二步和第三步的順序無法保證。如果第三步先執(zhí)行完畢、第二步未執(zhí)行時(shí),有另外的線程調(diào)用了instance,由于已經(jīng)賦值,將判斷不為null,拿去直接使用,但其實(shí)構(gòu)造函數(shù)還未執(zhí)行,成員變量等字段都未初始化,直接使用,就會(huì)報(bào)錯(cuò)。這就是DCL失效問題,而且很難復(fù)現(xiàn)。
對(duì)volatile變量的寫操作,不允許和它之前的讀寫操作打亂順序;對(duì)volatile變量的讀操作,不允許和它之后的讀寫亂序。
當(dāng)一個(gè)線程要使用共享內(nèi)存中的volatile變量時(shí),它會(huì)直接從主內(nèi)存中讀取,而不是使用自己本地內(nèi)存中的副本。當(dāng)一個(gè)線程對(duì)一個(gè)volatile變量進(jìn)行寫時(shí),它會(huì)將這個(gè)共享變量值刷新到共享內(nèi)存中。
枚舉類本節(jié)參考 http://blog.csdn.net/hxpjava1...
public enum Singleton{ instance; }
一個(gè)enum常量(這里是INSTANCE)代表了一個(gè)enum的實(shí)例,enum類型只能有這些常量實(shí)例。標(biāo)準(zhǔn)保證enum常量(INSTANCE)不能被克隆,也不會(huì)因?yàn)榉葱蛄谢a(chǎn)生不同的實(shí)例,想通過反射機(jī)制得到一個(gè)enum類型的實(shí)例也不行的。
避免序列化、反序列化時(shí)產(chǎn)生多個(gè)實(shí)例,有兩種解決方法
拋出異常
/** * prevent default deserialization */ private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { throw new InvalidObjectException("can"t deserialize enum"); }
在readResolve()方法中返回實(shí)例
ANY-ACCESS-MODIFIER Object writeReplace() throws ObjectStreamException; ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException;
以上兩個(gè)方法可以理解為序列化和反序列化過程的入口和出口。writeReplace()返回的對(duì)象,就是要被序列化的對(duì)象,我們有機(jī)會(huì)在序列化前把這個(gè)對(duì)象給換成我們確定好的那個(gè)(如果不是“故意搗亂”,暫時(shí)沒想到有什么用);而readResolve()方法就是在反序列化完成得到對(duì)象前,把這個(gè)對(duì)象給換成我們確定好的那個(gè)。
/** * 反序列化時(shí)內(nèi)存Hook這段代碼 * @return */ private Object readResolve() { return instance; }
靜態(tài)內(nèi)部類本節(jié)參考 http://837062099.iteye.com/bl...
內(nèi)部類的機(jī)制來巧妙實(shí)現(xiàn)懶漢式單例模式的實(shí)現(xiàn) :Lazy initialization holder class模式。
內(nèi)部類分為對(duì)象級(jí)別和類級(jí)別,類級(jí)內(nèi)部類指的是,有static修飾的成員變量的內(nèi)部類。如果沒有static修飾的成員變量的內(nèi)部類被稱為對(duì)象級(jí)內(nèi)部類。
類級(jí)內(nèi)部類相當(dāng)于其外部類的static成員,它的對(duì)象與外部類對(duì)象間不存在依賴關(guān)系,相互獨(dú)立,因此可直接創(chuàng)建。而對(duì)象級(jí)內(nèi)部類的實(shí)例,是必須綁定在外部對(duì)象實(shí)例上的。類級(jí)內(nèi)部類只有在第一次被使用的時(shí)候才被會(huì)裝載。采用類級(jí)內(nèi)部類,在這個(gè)類級(jí)內(nèi)部類里面去創(chuàng)建對(duì)象實(shí)例,能夠讓類裝載的時(shí)候不去初始化對(duì)象。
當(dāng)getInstance方法第一次被調(diào)用的時(shí)候,它第一次讀取SingletonHolder.instance,內(nèi)部類SingletonHolder類得到初始化;而這個(gè)類在裝載并被初始化的時(shí)候,會(huì)初始化它的靜態(tài)域,從而創(chuàng)建Singleton的實(shí)例,由于是靜態(tài)的域,因此只會(huì)在虛擬機(jī)裝載類的時(shí)候初始化一次,并由虛擬機(jī)來保證它的線程安全性。
這個(gè)模式的優(yōu)勢(shì)在于,getInstance方法并沒有被同步,并且只是執(zhí)行一個(gè)域的訪問,因此延遲初始化并沒有增加任何訪問成本。
public class Singleton{ private Singleton(){} private static class SingletonHolder{ private static final Singleton instance = new Singleton(); } public static Singleton getInstance(){ return SingletonHolder.instance; } }
本節(jié)參考 http://blog.csdn.net/hikvisio...
全文參考 http://blog.csdn.net/u0129753...
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/70130.html
摘要:一基礎(chǔ)接口的意義百度規(guī)范擴(kuò)展回調(diào)抽象類的意義想不想通過一線互聯(lián)網(wǎng)公司面試文檔整理為電子書掘金簡介谷歌求職記我花了八個(gè)月準(zhǔn)備谷歌面試掘金原文鏈接翻譯者 【面試寶典】從對(duì)象深入分析 Java 中實(shí)例變量和類變量的區(qū)別 - 掘金原創(chuàng)文章,轉(zhuǎn)載請(qǐng)務(wù)必保留原出處為:http://www.54tianzhisheng.cn/... , 歡迎訪問我的站點(diǎn),閱讀更多有深度的文章。 實(shí)例變量 和 類變量...
摘要:作者重慶森林鏈接來源牛客網(wǎng)整個(gè)三月份通過牛客網(wǎng)和網(wǎng)友分享的經(jīng)驗(yàn)學(xué)到了很多東西,現(xiàn)在反饋一下我的面試經(jīng)歷,希望對(duì)同學(xué)們有幫助。個(gè)人情況大三本方向渣碩,經(jīng)過實(shí)驗(yàn)室學(xué)長內(nèi)推,于三月底完成面試。校招是實(shí)力和運(yùn)氣的結(jié)合,缺一不可。 歡迎關(guān)注我的微信公眾號(hào):Java面試通關(guān)手冊(cè)(堅(jiān)持原創(chuàng),分享美文,分享各種Java學(xué)習(xí)資源,面試題,以及企業(yè)級(jí)Java實(shí)戰(zhàn)項(xiàng)目回復(fù)關(guān)鍵字免費(fèi)領(lǐng)取):showImg(h...
摘要:面試官要不你來手寫下單例模式唄候選者單例模式一般會(huì)有好幾種寫法候選者餓漢式簡單懶漢式在方法聲明時(shí)加鎖雙重檢驗(yàn)加鎖進(jìn)階懶漢式靜態(tài)內(nèi)部類優(yōu)雅懶漢式枚舉候選者所謂餓漢式指的就是還沒被用到,就直接初始化了對(duì)象。面試官:我看你的簡歷寫著熟悉常見的設(shè)計(jì)模式,要不你來簡單聊聊你熟悉哪幾個(gè)吧?候選者:常見的工廠模式、代理模式、模板方法模式、責(zé)任鏈模式、單例模式、包裝設(shè)計(jì)模式、策略模式等都是有所了解的候選者:...
摘要:本文介紹一些來自投資銀行的針對(duì)三年以上經(jīng)驗(yàn)的開發(fā)人員面試題。第七題和這兩個(gè)方法有什么不同答案本題取自我的投資銀行針對(duì)有經(jīng)驗(yàn)的開發(fā)者的五十個(gè)多線程面試題列表。總結(jié)以上就是投資銀行通常會(huì)出的面試題。 原文地址: https://dzone.com/articles/10... 有為數(shù)不少的開發(fā)者希望能在像 Barclays、Credit Suisse、Citibank 等等那樣的投資銀行做...
摘要:強(qiáng)大的表單驗(yàn)證前端掘金支持非常強(qiáng)大的內(nèi)置表單驗(yàn)證,以及。面向?qū)ο蠛兔嫦蜻^程的區(qū)別的種設(shè)計(jì)模式全解析后端掘金一設(shè)計(jì)模式的分類總體來說設(shè)計(jì)模式分為三大類創(chuàng)建型模式,共五種工廠方法模式抽象工廠模式單例模式建造者模式原型模式。 強(qiáng)大的 Angular 表單驗(yàn)證 - 前端 - 掘金Angular 支持非常強(qiáng)大的內(nèi)置表單驗(yàn)證,maxlength、minlength、required 以及 patt...
閱讀 1589·2023-04-26 01:54
閱讀 1621·2021-09-30 09:55
閱讀 2645·2021-09-22 16:05
閱讀 1856·2021-07-25 21:37
閱讀 2620·2019-08-29 18:45
閱讀 1886·2019-08-29 16:44
閱讀 1882·2019-08-29 12:34
閱讀 1346·2019-08-23 14:02