首先,還是貼一下單例的定義吧:
Ensure a class only has one instance,and provide a global point of access to it.
保證一個(gè)類僅有一個(gè)實(shí)例,并提供一個(gè)訪問它的全局訪問點(diǎn)。
開發(fā)常見一:雙重檢驗(yàn)鎖(jdk1.5以后使用關(guān)鍵字volatile才有意義)
使用volatile的原因(雖然沒看懂,但貼上吧,萬(wàn)一以后就看懂了呢):Java中的指令重排優(yōu)化。所謂指令重排優(yōu)化是指在不改變?cè)Z(yǔ)義的情況下,通過調(diào)整指令的執(zhí)行順序讓程序運(yùn)行的更快。JVM中并沒有規(guī)定編譯器優(yōu)化相關(guān)的內(nèi)容,也就是說JVM可以自由的進(jìn)行指令重排序的優(yōu)化。關(guān)鍵就在于由于指令重排優(yōu)化的存在,導(dǎo)致初始化Singleton和將對(duì)象地址賦給instance字段的順序是不確定的。在某個(gè)線程創(chuàng)建單例對(duì)象時(shí),在構(gòu)造方法被調(diào)用之前,就為該對(duì)象分配了內(nèi)存空間并將對(duì)象的字段設(shè)置為默認(rèn)值。此時(shí)就可以將分配的內(nèi)存地址賦值給instance字段了,然而該對(duì)象可能還沒有初始化。若緊接著另外一個(gè)線程來調(diào)用getInstance,取到的就是狀態(tài)不正確的對(duì)象,程序就會(huì)出錯(cuò)。 --------------------- 本文來自 viclee108 的CSDN 博客 ,全文地址請(qǐng)點(diǎn)擊:https://blog.csdn.net/goodlixueyong/article/details/51935526?utm_source=copy
//1、雙重檢驗(yàn)鎖 jdk1.5以后才能使用關(guān)鍵字volatile class Singleton1{ private static volatile Singleton1 instance=null; private Singleton1(){} public static Singleton1 newInstance(){ if(instance==null){ synchronized (Singleton1.class) { if(instance==null){ instance=new Singleton1(); } } } return instance; } }
開發(fā)常見二:靜態(tài)內(nèi)部類
//2、靜態(tài)內(nèi)部類 class Singleton2{ private static class SingletonHolder{ public static Singleton2 instance=new Singleton2(); } private Singleton2(){} public static Singleton2 newInstance(){ return SingletonHolder.instance; } }
枚舉實(shí)現(xiàn)單例:
//3、枚舉 enum Singleton3{ instance; public void method(){} }
在已知的單例實(shí)現(xiàn)方法中,除了枚舉法外,都有兩個(gè)共同的缺點(diǎn),我直接貼過來吧;
而枚舉類很好的解決了這兩個(gè)問題,使用枚舉除了線程安全和防止反射調(diào)用構(gòu)造器之外,還提供了自動(dòng)序列化機(jī)制,防止反序列化的時(shí)候創(chuàng)建新的對(duì)象。
雙重校驗(yàn)鎖和靜態(tài)內(nèi)部類的方式可以解決大部分問題,平時(shí)工作中使用的最多的也是這兩種方式。枚舉方式雖然很完美的解決了各種問題,但是這種寫法多少讓人感覺有些生疏。在沒有特殊需求的情況下,使用雙重校驗(yàn)鎖和靜態(tài)內(nèi)部類的方式實(shí)現(xiàn)單例模式。
聯(lián)系客服