單元素的枚舉類型已經(jīng)成為實現(xiàn)Singleton的最佳方法
????????????????????? -- 出自 《effective java》
1.單例的餓漢模式
1 public class Singleton { 2 /* 3 * 利用靜態(tài)變量來記錄Singleton的唯一實例 4 * 直接初始化靜態(tài)變量,這樣就可以確保線程安全了 5 */ 6 private static Singleton uniqueInstance = new Singleton(); 7 8 /* 9 * 構(gòu)造器私有化,只有Singleton類內(nèi)才可以調(diào)用構(gòu)造器10 */11 private Singleton(){1213 }1415 public static Singleton getInstance(){16 return uniqueInstance;17 }1819 }
2.懶漢的雙重加鎖機制
1 public class Singleton { 2 /* 3 * 利用靜態(tài)變量來記錄Singleton的唯一實例 4 * volatile 關(guān)鍵字確保:當uniqueInstance變量被初始化成Singleton實例時, 5 * 多個線程正確地處理uniqueInstance變量 6 * 7 */ 8 private volatile static Singleton uniqueInstance; 910 /*11 * 構(gòu)造器私有化,只有Singleton類內(nèi)才可以調(diào)用構(gòu)造器12 */13 private Singleton(){1415 }1617 /*18 *19 * 檢查實例,如果不存在,就進入同步區(qū)域20 */21 public static Singleton getInstance(){22 if(uniqueInstance == null){23 synchronized(Singleton.class){ //進入同步區(qū)域24 if(uniqueInstance == null){ //在檢查一次,如果為null,則創(chuàng)建25 uniqueInstance = new Singleton();26 }27 }28 }2930 return uniqueInstance;31 }3233 }
3.靜態(tài)內(nèi)部類
public class Singleton { private static class LazyHolder { private static final Singleton INSTANCE = new Singleton(); } private Singleton (){} public static final Singleton getInstance() { return LazyHolder.INSTANCE; } }
《effective java》中只簡單的提了幾句話:“享有特權(quán)的客戶端可以借助AccessibleObject.setAccessible方法,通過反射機制調(diào)用私有構(gòu)造器。如果需要低于這種攻擊,可以修改構(gòu)造器,讓它在被要求創(chuàng)建第二個實例的時候拋出異常。
任何一個readObject方法,不管是顯式的還是默認的,它都會返回一個新建的實例,這個新建的實例不同于該類初始化時創(chuàng)建的實例。”當然,這個問題也是可以解決的,想詳細了解的同學可以翻看《effective java》第77條:對于實例控制,枚舉類型優(yōu)于readResolve
public enum EnumSingleton { INSTANCE; public EnumSingleton getInstance(){ return INSTANCE; }}
完整的枚舉單例
public class User { //私有化構(gòu)造函數(shù) private User(){ } //定義一個靜態(tài)枚舉類 static enum SingletonEnum{ //創(chuàng)建一個枚舉對象,該對象天生為單例 INSTANCE; private User user; //私有化枚舉的構(gòu)造函數(shù) private SingletonEnum(){ user=new User(); } public User getInstnce(){ return user; } } //對外暴露一個獲取User對象的靜態(tài)方法 public static User getInstance(){ return SingletonEnum.INSTANCE.getInstnce(); }}public class Test { public static void main(String [] args){ System.out.println(User.getInstance()); System.out.println(User.getInstance()); System.out.println(User.getInstance()==User.getInstance()); }}結(jié)果為true
至此,相信同學們應(yīng)該能明白了為什么Joshua Bloch說的“單元素的枚舉類型已經(jīng)成為實現(xiàn)Singleton的最佳方法”了吧。