Inspired by Effective Java.
Singleton模式是在編程實(shí)踐中應(yīng)用最廣泛的幾種設(shè)計(jì)模式之一,。以前知道的,,實(shí)現(xiàn)單例的方法有兩種(下面的A、B),。剛剛在讀《Effective Java的時(shí)候》學(xué)到一種新的更好的方法(E):?jiǎn)卧氐拿杜e類型,。同時(shí)通過(guò)網(wǎng)上資料也知道了其他兩種方法(C、D),。最后一種在Java中從1.5版本開(kāi)始支持,,其他語(yǔ)言在驗(yàn)證后說(shuō)明。
A.餓漢式(類加載的時(shí)候就創(chuàng)建實(shí)例),。 代碼如下:
public class MaYun { public static final Mayun instance = new Mayun(); //靜態(tài)的final的MaYun private MaYun() { //MaYun誕生要做的事情 } public void splitAlipay() { System.out.println(“Alipay是我的啦,!看你丫Yahoo綠眉綠眼的望著。,。,?!?; } } Call:MaYun.instance.splitAlipay();
Feature:可以通過(guò)反射機(jī)制攻擊;線程安全[多個(gè)類加載器除外],。
A+.餓漢變種[推薦]
public class MaYun { private static Mayun instance = new Mayun(); private static getInstance() { return instance; } private MaYun() { //MaYun誕生要做的事情 } public void splitAlipay() { System.out.println(“Alipay是我的啦,!看你丫Yahoo綠眉綠眼的望著。,。,。”); } }
A++.餓漢變種(類初始化的時(shí)候?qū)嵗痠nstance):
public class MaYun { private MaYun instance = null; static { instance = new MaYun(); } private MaYun() { //MaYun誕生要做的事情 } public static MaYun getInstance() { return this.instance; } public void splitAlipay() { System.out.println(“Alipay是我的啦,!看你丫Yahoo綠眉綠眼的望著,。。,?!?; } }
B.懶漢式。 代碼如下:
public class MaYun { private static MaYun instance = null; private MaYun() { //MaYun誕生要做的事情 } public static MaYun getInstance() { if (instance == null) { instance = new MaYun(); } return instance; } public void splitAlipay() { System.out.println(“Alipay是我的啦,!看你丫Yahoo綠眉綠眼的望著,。。,?!?; } } Call:MaYun.getInstance().splitAlipay();
Feature:延時(shí)加載;線程不安全,,多線程下不能正常工作,;需要額外的工作(Serializable、transient,、readResolve())來(lái)實(shí)現(xiàn)序列化,。
B+.懶漢式變種。
public class MaYun { private static MaYun instance = null; private MaYun() { //MaYun誕生要做的事情 } public static synchronized MaYun getInstance() { if (instance == null) { instance = new MaYun(); } return instance; } public void splitAlipay() { System.out.println(“Alipay是我的啦,!看你丫Yahoo綠眉綠眼的望著,。。,?!?; } }
Feature:線程安全;效率比較低,,因?yàn)樾枰€程同步的時(shí)候比較少,。
C.靜態(tài)內(nèi)部類[推薦]。 代碼如下:
public class MaYun { private static class SigletonHolder { private static final instance = new MaYun(); } public static final getInstance() { return SigletonHolder.instance; } private MaYun() { //MaYun誕生要做的事情 } public void splitAlipay() { System.out.println(“Alipay是我的啦,!看你丫Yahoo綠眉綠眼的望著,。。,。”); } Call:MaYun.getInstance().splitAlipay();
Feature:線程安全;延遲加載,。
D.雙重校驗(yàn)鎖[不推薦],。 代碼如下:
public class MaYun { private volatile static MaYun instance; private MaYun (){} public static MaYun getInstance() { if (instance == null) { synchronized (MaYun.class) { if (instance == null) { instance = new MaYun(); } } } return instance; } }
Feature:jdk1.5之后才能正常達(dá)到單例效果。
E.編寫(xiě)一個(gè)包含單個(gè)元素的枚舉類型[極推薦],。 代碼如下:
public enum MaYun { himself; //定義一個(gè)枚舉的元素,,就代表MaYun的一個(gè)實(shí)例 private String anotherField; MaYun() { //MaYun誕生要做的事情 //這個(gè)方法也可以去掉。將構(gòu)造時(shí)候需要做的事情放在instance賦值的時(shí)候: /** himself = MaYun() { * //MaYun誕生要做的事情 * } **/ } public void splitAlipay() { System.out.println(“Alipay是我的啦,!看你丫Yahoo綠眉綠眼的望著,。。,?!?; } } Call:MaYun.himself.splitAlipay();
Feature:從Java1.5開(kāi)始支持;無(wú)償提供序列化機(jī)制,,絕對(duì)防止多次實(shí)例化,,即使在面對(duì)復(fù)雜的序列化或者反射攻擊的時(shí)候。
總之,,五類:懶漢,,惡漢,雙重校驗(yàn)鎖,,靜態(tài)內(nèi)部類,,枚舉。 惡漢:因?yàn)榧虞d類的時(shí)候就創(chuàng)建實(shí)例,,所以線程安全(多個(gè)ClassLoader存在時(shí)例外),。缺點(diǎn)是不能延時(shí)加載。 懶漢:需要加鎖才能實(shí)現(xiàn)多線程同步,,但是效率會(huì)降低,。優(yōu)點(diǎn)是延時(shí)加載。 雙重校驗(yàn)鎖:麻煩,,在當(dāng)前Java內(nèi)存模型中不一定都管用,,某些平臺(tái)和編譯器甚至是錯(cuò)誤的,因?yàn)閕nstance = new MaYun()這種代碼在不同編譯器上的行為和實(shí)現(xiàn)方式不可預(yù)知,。 靜態(tài)內(nèi)部類:延遲加載,,減少內(nèi)存開(kāi)銷。因?yàn)橛玫降臅r(shí)候才加載,,避免了靜態(tài)field在單例類加載時(shí)即進(jìn)入到堆內(nèi)存的permanent代而永遠(yuǎn)得不到回收的缺點(diǎn)(大多數(shù)垃圾回收算法是這樣),。 枚舉:很好,不僅能避免多線程同步問(wèn)題,,而且還能防止反序列化重新創(chuàng)建新的對(duì)象,。但是失去了類的一些特性,,沒(méi)有延遲加載,用的人也太少了~~
以后多推廣推廣單元素枚舉這種更好的單例實(shí)現(xiàn)方式,。在項(xiàng)目中的代碼開(kāi)始修改實(shí)施
|