Java設(shè)計(jì)模式之單例模式
單例模式是指在項(xiàng)目運(yùn)行中,一個(gè)類不論有多少對(duì)他的調(diào)用者,他只會(huì)存在一個(gè)實(shí)例
例1,經(jīng)典單例模式:
public class SingleTon {
private static SingleTon singleTon = null;
private SingleTon() {
}
public static SingleTon getInstance() {
if (singleTon == null) {
singleTon = new SingleTon();
}
return singleTon;
}
}
例子中類的構(gòu)造函數(shù)私有,只能調(diào)用靜態(tài)方法getInstance( ),調(diào)用的時(shí)候會(huì)判斷當(dāng)前類有沒有被實(shí)例化,沒有則創(chuàng)建,有則返回這個(gè)已經(jīng)創(chuàng)建的實(shí)例。
但是經(jīng)典單例模式也存在問題,當(dāng)多線程操作的時(shí)候,由于多線程的實(shí)際是時(shí)間片的切換,所以當(dāng)一個(gè)線程運(yùn)行到if(singleTon == null)判斷為true,準(zhǔn)備進(jìn)入下一行,進(jìn)行實(shí)例化的時(shí)候,多線程切換到另一個(gè)線程,這時(shí)候到同樣的位置,依然為true,繼續(xù)實(shí)例化,然后當(dāng)切回之前的線程依然會(huì)實(shí)例化,導(dǎo)致存在兩個(gè)實(shí)例,單例模式也就失敗了,對(duì)于這個(gè)問題進(jìn)行優(yōu)化。
例2 餓漢模式
public class SingleTon {
private static SingleTon singleTon = new SingleTon();
private SingleTon() {
}
public static SingleTon getInstance() {
if (singleTon == null) {
singleTon = new SingleTon();
}
return singleTon;
}
}
餓漢模式就是在,調(diào)用getInstance( )方法之前就進(jìn)行實(shí)例化,不管這個(gè)類有沒有被調(diào)用JVM中都會(huì)存在該類的實(shí)例。
例3 懶漢模式
public class SingleTon {
private static SingleTon singleTon = null;
private SingleTon() {
}
public synchronized static SingleTon getInstance() {
if (singleTon == null) {
singleTon = new SingleTon();
}
return singleTon;
}
}
懶漢模式就是在,調(diào)用getInstance( )方法時(shí)候使用synchronized進(jìn)行同步化,必須等到一個(gè)線程中的該方法執(zhí)行完成后,再會(huì)被其他線程調(diào)用
餓漢模式在自己被加載時(shí)就將自己實(shí)例化,如果從資源利用效率角度來講,比懶漢模式稍差些。但是從速度和反應(yīng)時(shí)間以及性能的角度來講,卻要比懶漢模式要稍好些
例4 雙重檢查加鎖
public class SingleTon {
//volatile關(guān)鍵字是為了禁止編譯器對(duì) volatile關(guān)鍵字修飾的變量進(jìn)行重排序,
//并保證volatile變量的讀操作發(fā)生在寫操作之后
private volatile static SingleTon singleTon = null;
private SingleTon() {
}
public static SingleTon getInstance() {
if (singleTon == null) {
synchronized (SingleTon.class) {
if (singleTon == null) {
singleTon = new SingleTon();
}
}
}
return singleTon;
}
}
這樣的做法會(huì)對(duì)創(chuàng)建對(duì)象進(jìn)行兩次檢查,其中一次檢查加入了同步方法,而當(dāng)?shù)诙握{(diào)用的時(shí)候不會(huì)再因?yàn)橥椒椒ㄏ男阅?,該方法也很好的解決了多線程的情況下單例模式消耗資源的問題。
例5 靜態(tài)內(nèi)部類
public class SingleTon { //完成了懶漢式的延遲加載,同時(shí)static保證了線程安全。
private SingleTon(){
}
public static SingleTon getIntance(){
return SingletonHolder.mIntance;
}
//私有的,初始化的時(shí)候,沒有調(diào)用getIntance方法則不會(huì)加載
private static class SingletonHolder{
//static,final是jvm提供的同步機(jī)制,初始化后就無法修改了
private static final SingleTon mIntance = new SingleTon();
}
}
這種寫法是最為推崇的寫法,利用static final關(guān)鍵字的同步機(jī)制,初始化后就無法修改保證了線程安全,使用holder的方式保證了延遲加載,不適用不會(huì)被加載
參考代碼鏈接
Gitee: https://gitee.com/singlekingdom/JavaDesignPatterns.git