1.某個線程修改了被volatile關(guān)鍵字修飾變量是,根據(jù)數(shù)據(jù)一致性的協(xié)議嘶伟,
通過信號量又碌,更改其他線程的高速緩存中volatile關(guān)鍵字修飾變量狀態(tài)為無效狀態(tài),
其他線程如果需要重寫讀取該變量會再次從主內(nèi)存中讀取毕匀,而不是讀取自己的高速緩存中的。
2.被volatile關(guān)鍵字修飾變量不會指令重排序蹋笼。
注意:volatile 不是原子性的,所以不能保證并發(fā)問題
如:volatile 修飾一個變量 i = ,0剖毯,開辟十個線程,執(zhí)行1000次i++擂达,結(jié)果是不能保證值為1000胶滋,
public class VolatileTest {
public volatile int inc = 0;
public void increase() {
inc++;
}
public static void main(String[] args) throws InterruptedException {
final VolatileTest test = new VolatileTest();
for (int i = 0; i < 10; i++) {
new Thread(() -> {
for (int j = 0; j < 1000; j++)
test.increase();
}).start();
}
//保證前面的線程都執(zhí)行完
Thread.sleep(3000);
System.out.println(test.inc);
}
}
多次運行main函數(shù),你會發(fā)現(xiàn)結(jié)果永遠(yuǎn)都不會為10000俭令,都是小于10000』秸幔可能有這樣的疑問窟赏,volatile保證了共享數(shù)據(jù)的可見性,線程1修改了inc變量線程2會重新從主內(nèi)存中重新讀涯穷,這樣就能保證inc++的正確性了啊,可為什么沒有得到我們預(yù)期的結(jié)果呢作煌?
在之前已經(jīng)講述過inc++這樣的操作不是一個原子性操作赚瘦,它分為讀、加加起意、寫。一種情況悲酷,當(dāng)線程1讀取了inc的值亲善,還沒有修改,線程2也讀取了顿肺,線程1修改完了,通知線程2將線程的緩存的 inc的值無效需要重讀挟冠,可這時它不需要讀取inc ,它仍執(zhí)行寫操作知染,然后賦值給主線程,這時數(shù)據(jù)就會出現(xiàn)問題嫌吠。
所以volatile不能保證原子性 掺炭。這時需要用鎖來保證,在increase方法加上synchronized,重新運行打印的結(jié)果為10000 炕矮。
public synchronized void increase() {
inc++;
}