1 單例模式
單例模式:確保某一個(gè)類只有一個(gè)實(shí)例,自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例。
使用場(chǎng)景
確保某個(gè)類只有一個(gè)對(duì)象的場(chǎng)景,避免產(chǎn)生多個(gè)對(duì)象消耗資源,或者某個(gè)對(duì)象應(yīng)該有且只有一個(gè)的場(chǎng)景。
特點(diǎn)
1.構(gòu)造函數(shù)不對(duì)外開放,一般為private
2.通過(guò)靜態(tài)方法返回單例類的對(duì)象
3.確保對(duì)象只有一個(gè),尤其是在多線程的情況下
4.確保單例類對(duì)象在反序列化時(shí)不會(huì)重新創(chuàng)建對(duì)象
寫單例
一:餓漢模式
public class Singleton {
private static final Singleton singleton = new Singleton();
private Singleton(){
}
public static Singleton getInstance(){
return singleton;
}
// do.....
}
二:懶漢模式
public class SingletonV2 {
private static SingletonV2 singletonV2 = null;
private SingletonV2(){
}
public static synchronized SingletonV2 getInstance(){
if(singletonV2 != null){
singletonV2 = new SingletonV2();
}
return singletonV2;
}
// do....
}
優(yōu)點(diǎn):只有在使用時(shí)才會(huì)被實(shí)例化
缺點(diǎn):每次使用都要進(jìn)行同步,即使單例已經(jīng)存在,造成不必要的同步開銷
三:DCL實(shí)現(xiàn)單例(雙鎖)
public class SingletonV3 {
private static SingletonV3 singletonV3 = null;
private SingletonV3(){
}
public static SingletonV3 getInstance(){
if(singletonV3 == null){
synchronized (SingletonV3.class){
if(singletonV3 == null){
singletonV3 = new SingletonV3();
}
}
}
return singletonV3;
}
// do ....
}
DCL失效問(wèn)題:
singletonV3 = new SingletonV3(); 一句代碼,卻不是原子性操作,會(huì)被編譯成多條匯編指令,但大致作了三件事:
1.給SingletonV3的實(shí)例分配內(nèi)存;
2.調(diào)用SingletonV3的構(gòu)造函數(shù),初始化字段;
3.將singletonV3指向分配的內(nèi)存空間(這時(shí)singletonV3 不為 null)
JDK1.5之前java編譯器允許處理器亂序執(zhí)行,上面2,3的執(zhí)行順序是無(wú)法保證的,所以執(zhí)行順序可能是1-2-3,也可能是1-3-2,如果是后者,則有可能出現(xiàn)3執(zhí)行完畢,2還未執(zhí)行,此時(shí)singletonV3已經(jīng)不為null,但另一個(gè)線程取走singletonV3,使用就會(huì)出錯(cuò)。
jdk1.5之后,使用volatile,修改為private volatile static SingletonV3 singletonV3 = null;就可以保證singletonV3保證每次都是從主內(nèi)存中讀取。
能夠在絕大多數(shù)情況保證單例對(duì)象的唯一性,除非在并發(fā)場(chǎng)景比較復(fù)雜或JDK低于6的版本下使用。
四:靜態(tài)內(nèi)部類實(shí)現(xiàn)
public class SingletonV4 {
private SingletonV4(){
}
public static SingletonV4 getInstance(){
return SingletonHolder.singletonV4;
}
private static class SingletonHolder{
private static final SingletonV4 singletonV4 = new SingletonV4();
}
}
第一次加載SingletonV4時(shí)并不會(huì)初始化singletonV4,只有第一次調(diào)用getInstance()才會(huì)導(dǎo)致加載SingletonHolder類,線程安全,而且保證對(duì)象的唯一性,切延遲實(shí)例化,推薦的單例實(shí)現(xiàn)方式。
五:枚舉實(shí)現(xiàn)單例
public enum SIngletonEnum {
Instance;
// do something
private int num = 10;
public int doSomething(){
return num;
}
//
}
枚舉單例的最大特點(diǎn)就是簡(jiǎn)單,枚舉不僅能夠有字段,還能夠有方法,枚舉單例是線程安全的。
反序列化
序列化操作提供了一個(gè)很特別的鉤子(hook)-類中具有一個(gè)私有的被實(shí)例化的方法readresolve(),這個(gè)方法可以確保類的開發(fā)人員在序列化將會(huì)返回怎樣的object上具有發(fā)言權(quán)。
private Object readResolve() throws ObjectStreamException {
return getInstance();
}