提起單例模式,作為攻城獅的你我都不會(huì)感覺(jué)到陌生,而為了確保在程序中的線(xiàn)程安全,我們常常會(huì)傾向于雙重校驗(yàn)和靜態(tài)類(lèi)兩種方式。而且眾所周知,在雙重校驗(yàn)的方式中,我們發(fā)現(xiàn)了關(guān)鍵字volatile的身影,而且一直以來(lái)小編只是知道 該關(guān)鍵字可以保證操作之間的可見(jiàn)性。但是只知其一啊,今天突然明白這其中的道理:
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
如上述代碼片所示,singleton變量使用了volatile關(guān)鍵字修飾,也就意味著這個(gè)變量對(duì)接下來(lái)的操作具有可見(jiàn)性(原因稍后會(huì)有解釋?zhuān)?br>
? 如果上述代碼中singleton變量去掉volatile關(guān)鍵字……
public class Singleton {
private static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
如上述代碼所示,如果是單線(xiàn)程操作,由于代碼的順序間接的決定了執(zhí)行順序,而且在單線(xiàn)程中,即使jvm執(zhí)行了順序重排,仍然不會(huì)出現(xiàn)問(wèn)題;
在討論多線(xiàn)程的場(chǎng)景之前,我們先來(lái)科普一下 對(duì)象初始化的過(guò)程:在對(duì)象初始化也就是如第八行代碼(singleton = new Singleton(); )所示,要知道,這行代碼一共有三個(gè)過(guò)程:
分配對(duì)象的內(nèi)存空間-->初始化對(duì)象 --> 將singleton指向剛分配好的內(nèi)存地址
-----------------------------------------我是分割線(xiàn)-------------------------------------------
明白初始化的過(guò)程之后,我們開(kāi)始討論多線(xiàn)程的場(chǎng)景:假設(shè)現(xiàn)在有線(xiàn)程A和線(xiàn)程B,當(dāng)兩個(gè)線(xiàn)程同時(shí)來(lái)訪(fǎng)問(wèn)Singleton對(duì)象,但是在訪(fǎng)問(wèn)期間會(huì)有以下不安全的情況:
1)A /B 線(xiàn)程同時(shí)訪(fǎng)問(wèn),這時(shí)兩個(gè)線(xiàn)程都發(fā)現(xiàn)singleton為空,所以?xún)蓚€(gè)線(xiàn)程都會(huì)創(chuàng)建一個(gè)singleton變量,這自然不符合單例模式的初衷……
2)在不同的時(shí)間,A、B線(xiàn)程分別來(lái)訪(fǎng)問(wèn)這個(gè)Singleton對(duì)象,可能會(huì)出現(xiàn)報(bào)錯(cuò)的情況:

如上圖所示,線(xiàn)程B在T4時(shí)間的訪(fǎng)問(wèn)一定會(huì)出現(xiàn)NullPointerException,因?yàn)檎也坏竭@個(gè)對(duì)象噻!
關(guān)于volatile修飾之后,為什么就可以避免上圖中多線(xiàn)程訪(fǎng)問(wèn)的問(wèn)題,將在下篇中講解,敬請(qǐng)期待!
————————————————
版權(quán)聲明:本文為CSDN博主「楊士超」的原創(chuàng)文章,遵循CC 4.0 by-sa版權(quán)協(xié)議,轉(zhuǎn)載請(qǐng)附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/YSC1123/article/details/77867138