雙重檢驗的單例模式是比較推薦的單例寫法,在該代碼中的單例對象的是用volatile關鍵字修飾的。這時就產生的一個疑問,為什么需要volatile來修飾呢?
上網查看多個博客,下面簡單通俗分析一下當中的原因:
貼上不加volatile單例代碼
public class Singleton {
private static Singleton s;
private Singleton(){};
public static Singleton getInstance() { //1
if(s == null) { //2
synchronized (Singleton.class) { //3
if(s == null) { //4
s = new Singleton(); //5
}
}
}
return s; //6
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
以前不了解為什么需要volatile關鍵字,后來發現在並發情況下,如果沒有volatile關鍵字,在第5行會出現問題
對於第5行 s = new Singleton(); //5
可以分解為3個步驟:
1 memory=allocate();// 分配內存 相當於c的malloc
2 ctorInstanc(memory) //初始化對象
3 s=memory //設置s指向剛分配的地址
上面的代碼在編譯器運行時,可能會出現重排序 從1-2-3 排序為1-3-2
如此在多線程下就會出現問題
例如現在有2個線程A,B
線程A在執行第5行代碼時,B線程進來,而此時A執行了 1和3,沒有執行2,此時B線程判斷s不為null 直接返回一個未初始化的對象,就會出現問題
而用了volatile,上面的重排序就會在多線程環境中禁止,不會出現上述問題。
正確雙重檢驗單例模式寫法:
public class Singleton {
private static volatile Singleton s;
private Singleton(){};
public static Singleton getInstance() {
if(s == null) {
synchronized (Singleton.class) {
if(s == null) {
s = new Singleton();
}
}
}
return s;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
總結:加上volatile就是為了防止產生指令的重排序問題
為什么volatile能禁止指令的重排序呢?這里就涉及到volatile的原理了,這里就不多說volatile的原理,可以看看海子大神的博客:volatile關鍵字解析
---------------------
作者:Tuzki_小辣雞
來源:CSDN
原文:https://blog.csdn.net/weixin_37659242/article/details/82776198
版權聲明:本文為博主原創文章,轉載請附上博文鏈接!