常見的單例模式是針對一個線程的情況下實現沒問題,但是當多個線程去請求資源的時候,可能出現產生多個對象,採用synchronized上鎖可以解決99.9%這一問題,但是仍可能存在指令重排的情況(數據之間沒有依賴性,底層編譯的時候可能指令沒按順序),這一情況,使用volatile關鍵字修飾變量可以得到很好的解決。因爲volatile關鍵字可以反正指令重排。
volatile實現禁止指令重排優化,從而避免多線程環境下程序出現亂序執行的現象
先了解一個概念,內存屏障(Memory Barrier) 又稱內存柵欄,是一個CPU指令,它的作用有兩個:
一是保證特定操作的執行順序,
二是保證某些變量的內存可見性( 利用該特性實現volatile的內存可見性)。
由於編譯器和處理器都能執行指令重排優化。如果在指令間插入一條MemoryBarrier則會告訴編譯器和CPU,不管什麼指令都不能,
和這條Memory Barrier指令重排序,也就是說通過插入內存屏障禁止在內存屏障前後的指令執行重排序優化。內存屏障另外一個作
用是強制刷出各種CPU的緩存數據,因此任何CPU上的線程都能讀取到這些數據的最新版本。
public class SingletonDemo {
//使用volatile修飾變量
private static volatile SingletonDemo singletonDemo=null;
public SingletonDemo() {
System.out.println(Thread.currentThread().getName()+"==currentThreadName");
}
//採用雙重檢查鎖模式,但還是可能存在指令重排的情況,使用volatile關鍵字可以避免
public static SingletonDemo getInstance(){
if (singletonDemo==null){
synchronized (SingletonDemo.class){
if (singletonDemo==null){
singletonDemo=new SingletonDemo();
}
}
}
return singletonDemo;
}
public static void main(String[] args) {
for (int i=0;i<10;i++){
new Thread(()->{
SingletonDemo.getInstance();
},String.valueOf(i)).start();
}
}
}