volatile

1.禁止指令重排序

``
public class VoliatlieTest3 {

private volatile VoliatlieTest3 singleInstace;

private VoliatlieTest3() {
}

public VoliatlieTest3 getSingleInstace() {
    if (singleInstace == null) {            
        synchronized (VoliatlieTest3.class) {
            if (singleInstace == null) {
                singleInstace = new VoliatlieTest3();
            }
        }
    }
    return singleInstace;
}

}
``
singleInstace = new VoliatlieTest3()
這個代碼分3個指令:
1.分配內(nèi)存空間
2.初始化對象
3.將singleTon指向分配的內(nèi)存
第二步和第三步可能會次序不一樣

那么多線程這里會出問題
現(xiàn)在有線程A,B
如果A線程運行到singleInstace = new VoliatlieTest3(),并且這里指令被重新排序了,現(xiàn)在執(zhí)行執(zhí)行了
1.分配內(nèi)存空間
2.將singleInstace指向分配的內(nèi)存
執(zhí)行到這里的時候singleInstace就!= null了,但實際還是空的
這個時候線程B正好過來了,判斷singleInstace 不為空,然后返回了,此時B線程返回的就是空的對象

2.保證對象(基本數(shù)據(jù)類型)可見性,

``
public class VoliatlieTest2 extends Thread {

//這里  volatile 會使線程內(nèi)存中的變量從主內(nèi)存中獲取flat,如果沒有這個關(guān)鍵字,則下面的進程不會退出,每次打印的i都是不一樣的;
volatile boolean flat = false;
int i = 0;

@Override
public void run() {
    while (!flat) { i++; }
}

public static void main(String[] args) {
    VoliatlieTest2 voliatlieTest2 = new VoliatlieTest2();
    voliatlieTest2.start();
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    voliatlieTest2.flat = true;
    System.out.println(voliatlieTest2.i);
    System.out.println(voliatlieTest2.i);
}

}
``
主線程里面,flat 初始值是false, i初始值是0
子線程voliatelieTest2啟動起來后,如果flat是false對i進行++,主線程休眠1秒主線程將flat改為true
打印2次i的變量
這里雖然將flat改為true了,但是子線程還會對執(zhí)行i++,可以理解為子線程操作的是自己內(nèi)存中的那個flat, 沒有和主線程中的flat進行同步,主線程的flat被改為true了 但是子線程讀取的flat還是flase,如果flat用volatile修飾,主線程將flat改為true后,子線程讀取的flat就會是true 也就是i++就不會再執(zhí)行了,打印的值就是相同的數(shù)

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

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

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