1.引言
單元素的枚舉類型已經(jīng)成為實(shí)現(xiàn)Singleton的最佳方法
????????????????????? -- 出自 《effective java》
2.單例模式的特點(diǎn)
- 單例模式三個(gè)主要特點(diǎn):
1、構(gòu)造方法私有化赋访;
2佣耐、實(shí)例化的變量引用私有化;
3、獲取實(shí)例的方法共有益楼。
3. 常用的單例模式
1.單例的餓漢模式
1 public class Singleton {
2 /*
3 * 利用靜態(tài)變量來記錄Singleton的唯一實(shí)例
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(){
12
13 }
14
15 public static Singleton getInstance(){
16 return uniqueInstance;
17 }
18
19 }
2.懶漢的雙重加鎖機(jī)制
1 public class Singleton {
2 /*
3 * 利用靜態(tài)變量來記錄Singleton的唯一實(shí)例
4 * volatile 關(guān)鍵字確保:當(dāng)uniqueInstance變量被初始化成Singleton實(shí)例時(shí),
5 * 多個(gè)線程正確地處理uniqueInstance變量
6 *
7 */
8 private volatile static Singleton uniqueInstance;
9
10 /*
11 * 構(gòu)造器私有化赌蔑,只有Singleton類內(nèi)才可以調(diào)用構(gòu)造器
12 */
13 private Singleton(){
14
15 }
16
17 /*
18 *
19 * 檢查實(shí)例俯在,如果不存在,就進(jìn)入同步區(qū)域
20 */
21 public static Singleton getInstance(){
22 if(uniqueInstance == null){
23 synchronized(Singleton.class){ //進(jìn)入同步區(qū)域
24 if(uniqueInstance == null){ //在檢查一次娃惯,如果為null跷乐,則創(chuàng)建
25 uniqueInstance = new Singleton();
26 }
27 }
28 }
29
30 return uniqueInstance;
31 }
32
33 }
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;
}
}
4.為什么使用單例
4.1 私有化構(gòu)造器并不保險(xiǎn)
《effective java》中只簡單的提了幾句話:“享有特權(quán)的客戶端可以借助AccessibleObject.setAccessible方法,通過反射機(jī)制調(diào)用私有構(gòu)造器趾浅。如果需要低于這種攻擊愕提,可以修改構(gòu)造器,讓它在被要求創(chuàng)建第二個(gè)實(shí)例的時(shí)候拋出異常皿哨。
4.2序列化問題
任何一個(gè)readObject方法浅侨,不管是顯式的還是默認(rèn)的,它都會(huì)返回一個(gè)新建的實(shí)例证膨,這個(gè)新建的實(shí)例不同于該類初始化時(shí)創(chuàng)建的實(shí)例如输。”當(dāng)然央勒,這個(gè)問題也是可以解決的不见,想詳細(xì)了解的同學(xué)可以翻看《effective java》第77條:對(duì)于實(shí)例控制,枚舉類型優(yōu)于readResolve
4.3 枚舉單例示例
public enum EnumSingleton {
INSTANCE;
public EnumSingleton getInstance(){
return INSTANCE;
}
}
單例模式
public class User {
//私有化構(gòu)造函數(shù)
private User(){ }
//定義一個(gè)靜態(tài)枚舉類
static enum SingletonEnum{
//創(chuàng)建一個(gè)枚舉對(duì)象崔步,該對(duì)象天生為單例
INSTANCE;
private User user;
//私有化枚舉的構(gòu)造函數(shù)
private SingletonEnum(){
user=new User();
}
public User getInstnce(){
return user;
}
}
//對(duì)外暴露一個(gè)獲取User對(duì)象的靜態(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
以上代碼看起來已經(jīng)是ok了稳吮,其實(shí)不是,可能還存在反射攻擊或者反序列化攻擊
最終版
public enum Singleton {
INSTANCE;
public void doSomething() {
System.out.println("doSomething");
}
}
調(diào)用方法:
public class Main {
public static void main(String[] args) {
Singleton.INSTANCE.doSomething();
}
}
直接通過Singleton.INSTANCE.doSomething()的方式調(diào)用即可井濒。方便灶似、簡潔又安全。
5.總結(jié)
至此瑞你,相信大家應(yīng)該能明白了為什么Joshua Bloch說的“單元素的枚舉類型已經(jīng)成為實(shí)現(xiàn)Singleton的最佳方法”了吧喻奥。