簡(jiǎn)單聊聊單例模式

單例模式應(yīng)該是Android開(kāi)發(fā)中常用的一種設(shè)計(jì)模式。不僅我們經(jīng)常用到,Android源碼中也經(jīng)??梢钥吹絾卫J降倪\(yùn)用。

單例模式很簡(jiǎn)單,但我相信有的同學(xué)并沒(méi)有完全搞清楚,平時(shí)寫單例模式也就隨便找一個(gè)模板就開(kāi)始用。

廢話不多說(shuō),下面正式開(kāi)始。


單例模式分為:

餓漢

懶漢

懶漢線程安全

DCL

靜態(tài)內(nèi)部類


餓漢

public class TestMode {

private static final TestMode testMode = new TestMode();

private TestMode(){

System.out.println("TestMode 初始化完成");

}

public static TestMode getInstance(){

return testMode;

}

public?static void doSomething(){

System.out.println("doSomething");

}

}

我們?cè)趍ain函數(shù)中調(diào)用doSomething方法,運(yùn)行結(jié)果為:

餓漢式運(yùn)行結(jié)果

上面是餓漢式的單例模式,我們可以看到類的對(duì)象在還沒(méi)有使用getInstance方法的時(shí)候就已經(jīng)初始化完成了,這樣就會(huì)對(duì)內(nèi)存造成不必要的消耗。


懶漢

public class TestMode {

private static TestMode testMode;

private TestMode() {

System.out.println("TestMode 初始化完成");

}

public static TestMode getInstance() {

if (testMode ==null) {

testMode = new TestMode();

}

return testMode;

}

public static void doSomething() {

System.out.println("doSomething");

}

}

我們?cè)趍ain函數(shù)中調(diào)用doSomething方法,運(yùn)行結(jié)果為:

懶漢式運(yùn)行結(jié)果

以上是懶漢式,我們可以看到調(diào)用類中的其他方法并不會(huì)創(chuàng)建實(shí)例,而是在調(diào)用getInstance方法之后才會(huì)創(chuàng)建實(shí)例。但是這里會(huì)出現(xiàn)一個(gè)問(wèn)題,當(dāng)我們?cè)诙嗑€程中調(diào)用getInstance方法的時(shí)候會(huì)存在線程不安全的情況。

例:

測(cè)試方法

我們用以上的測(cè)試方法,得到的測(cè)試結(jié)果為:

測(cè)試結(jié)果

我們可以看到,這里的測(cè)試結(jié)果中我們有兩次初始化了TestMode。所以懶漢式有線程不安全的問(wèn)題。那么我們?nèi)绾谓鉀Q這個(gè)問(wèn)題呢,請(qǐng)大家往下面看。


懶漢線程安全

public class TestMode {

private static?volatile TestMode testMode;

private TestMode() {

System.out.println("TestMode 初始化完成");

}

public static synchronized TestMode getInstance() {

if (testMode ==null) {

testMode = new TestMode();

}

return testMode;

}

public static TestMode getInstance2() {

synchronized (TestMode.class) {

if (testMode ==null) {

testMode = new TestMode();

}

}

return testMode;

}

public static void doSomething() {

System.out.println("doSomething");

}

}

在代碼中加入了同步鎖和volatile關(guān)鍵字,這樣就保證了線程安全。上面的代碼中用了兩種方法來(lái)加入同步鎖,第一種是在方法上加入,第二種是在方法里面加入,這兩種都是可以的。我也用相同的測(cè)試方法測(cè)試多次,并沒(méi)有出現(xiàn)線程安全問(wèn)題。


DCL

上面的懶漢線程安全式因?yàn)榧尤肓送芥i,每次調(diào)用方法都會(huì)進(jìn)行上鎖,所以性能上會(huì)有一定的影響,這也是它的缺點(diǎn)。接下來(lái)我就給大家介紹一種更好的單例模式寫法,那就是DCL。

public class TestMode {

private static volatile TestMode testMode;

private TestMode() {

System.out.println("TestMode 初始化完成");

}

public static TestMode getInstance() {

if (testMode ==null) {

synchronized (TestMode.class) {

if (testMode ==null) {

testMode = new TestMode();

}

}

}

return testMode;

}

public static void doSomething() {

System.out.println("doSomething");

}

}

上面的代碼就是DCL,這個(gè)方式解決了線程安全問(wèn)題,同時(shí)也解決了性能問(wèn)題。


靜態(tài)內(nèi)部類

最后我再給大家介紹一種靜態(tài)內(nèi)部類的寫法,這種寫法代碼更加簡(jiǎn)潔,也不存在線程安全以及性能問(wèn)題。

public class TestMode {

private TestMode() {

System.out.println("TestMode 初始化完成");

}

public static TestMode getInstance() {

return TestModeHolder.testMode;

}

public static void doSomething() {

System.out.println("doSomething");

}

private static class TestModeHolder {

private static final TestMode testMode = new TestMode();

}

}

這個(gè)靜態(tài)內(nèi)部類的寫法其實(shí)是在餓漢式的基礎(chǔ)上進(jìn)行了改動(dòng),利用了類的特性,這樣在使用TestMode類中的其他方法的時(shí)候并不會(huì)初始化TestModeHolder類中對(duì)象。推薦大家以后使用這個(gè)寫法。


其實(shí)單例模式還有枚舉的寫法,只是現(xiàn)在Android不建議使用枚舉,所以我這里就不介紹了。文章很簡(jiǎn)單,如果有錯(cuò)誤的地方希望大家提出來(lái),我會(huì)對(duì)文章進(jìn)行改進(jìn)。馬上過(guò)完年又要開(kāi)始上班了,希望小伙伴們加油,早日用代碼改變世界?。?!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容