從三種單例模式的比較中瞭解volatile的真相

本想吟詩一首,奈何才疏學淺。
吼吼得了
/**
 * 加鎖懶漢式單例模式
 * 犧牲了性能(初始化後,仍會發生線程阻塞問題),保證了併發安全
 */
class SingleInstance2 {
    private static SingleInstance2 singleInstance2;
    public static synchronized SingleInstance2 getSingleInstance2(){
        if (singleInstance2 == null) {
            singleInstance2 = new SingleInstance2();
        }
        return singleInstance2;
    }
}
/**
 * 餓漢式,既能保證併發安全,也能保證性能
 * 缺點:類加載時就初始化,浪費內存
 */
class SingleInstance3 {
    private static final SingleInstance3 singleInstance3 = new SingleInstance3();
    public static SingleInstance3 getSingleInstance3() {
        return singleInstance3;
    }
}
 
volatile/單例模式  學習筆記 
/**
 * 雙重檢查鎖機制,兼顧性能與安全,初始化以後,不會發生線程阻塞
 * Java指令執行的過程:1.將變量從主存複製到線程的工做內存中;2.而後進行讀操做;3.有賦值指令時進行賦值操做;4.將結果寫入主存中;
 * 以上4步都是原子性的,但組合到一塊兒,多線程操做時不能保證總體原子性,這也就是線程併發安全問題的緣由。
 * 其中volatile修飾詞做用:
 * 1.某一線程對volatile修飾的變量進行修改後,會強制將結果寫入主存,並使其它線程緩存行失效(失效後,讀操做不能從工做內存中直接讀取,從步驟1開始),
 * 即保證3和4指令執行過程的總體原子性,並通知其它線程。
 * 2.禁止指令重排(代碼的編寫順序和指令執行的順序不一致),必定程度上保證了有序性。
 * @author: dreamMaker
 **/
public class SingleInstance {
    private static volatile SingleInstance singleInstance;
    public static SingleInstance getSingleInstance(){
        //非空則跳過,由於只有首次初始化纔有安全問題,保證了初始化以後,線程不會阻塞,提升了性能
        if (singleInstance == null) {
            synchronized(SingleInstance.class){
                //voliatile能保證可見性,但不能保證原子性,加鎖保證線程併發狀況下,也只有一個實例
                if (singleInstance == null) {
                    singleInstance = new SingleInstance();
                }
            }
        }
        return singleInstance;
    }
}
 
可能會用雙重所機制爲何要加volatile的疑問,提示:volatile會使其它線程的緩存行失效,讀操做須要從從新存中去取。
相關文章
相關標籤/搜索