併發程式設計基礎之volatile關鍵字的用法

2022-07-05 06:18:11 字數 1619 閱讀 2106

一:概念

volatile關鍵字是乙個輕量級的執行緒同步,它可以保證執行緒之間對於共享變數的同步,假設有兩個執行緒a和b,

它們都可以訪問乙個成員變數,當a修改成員變數的值的時候,要保證b也能夠取得成員變數最新的值,程式的

記憶體模型是這樣的,程式執行時,成員變數的值被載入到記憶體中,如果執行緒a執行時,會把變數的值拷貝到cpu分配

給a的快取記憶體區,就是記憶體的乙個副本,執行緒b執行時,會把變數拷貝到cpu分配給b的快取記憶體區,正常情況下,

a執行緒修改成員變數時,會將快取記憶體中的值寫入主存,然後b執行緒執行時讀取主存中值到快取,但是不是強制性的,

使用volatile關鍵字就是強制性。

1:將快取記憶體強制寫入主記憶體

2:會使b執行緒快取記憶體標記失效

二:比較經典的乙個示例

t1執行緒先啟動,然後一直列印『i love u』,這時t2執行緒啟動,將flag變數的值修改為true,然後t1執行緒的執行終止,如果flag變數不加volatile修飾,

出現死迴圈的概率是存在的,但是比較低,如果加volatile,會強制t2執行緒修改主記憶體中flag的值,而且t1執行緒快取記憶體標記會失效,可以保證

一定能夠終止t1程式的執行

/**

* */

package com.day2;

/** * @author administrator

* */

public class listadd1 }};

//執行緒2

thread t2 = new thread("t2")

};t1.start();

//保證t1執行緒先啟動

try catch (interruptedexception e)

t2.start(); }

}

private volatile boolean flag;

但是volatile並不能保證操作的原子性,執行緒搶到cpu的時間片,修改快取記憶體的值,寫入主記憶體這幾個過程不是原子的,

int i = 0;

i = i+1;

如果執行緒1在搶到cpu的時間片之後,還沒有修改快取記憶體的值,然後執行緒2也讀取了主記憶體中快取的值i = 0,然後執行加1,

寫入快取記憶體,執行緒1之前讀取快取中的值也是0,然後執行加1,寫入主記憶體,這樣就出現問題了,所以使用volatile不能

保證執行緒安全問題。

如下示例:

啟動10個執行緒,count初始值為0,正常情況,10個執行緒個迴圈1000次,最後的count值應該為10000,但是不是,這個值

是隨機的。

/**

* */

package com.day2;

/** * @author administrator

* */

public class listadd2

}}.start();

} system.out.println(list.count); }

}

如果想確保執行緒安全,那麼必須使用synchronized鎖

synchronized (list)

因為10個執行緒訪問的是同乙個例項,所以使用物件鎖就可以了。

併發程式設計 volatile

併發程式設計中的三個概念 原子性即乙個操作或者多個操作 要麼全部執行並且執行的過程不會被任何因素打斷,要麼就都不執行 可見性指當多個執行緒訪問同乙個變數時,乙個執行緒修改了這個變數的值,其他執行緒能夠立即看得到修改的值 有序性即程式執行的順序按照 的先後順序執行 jvm在真正執行這段 的時候會保證語...

併發程式設計(3)volatile

原子性,可見性,有序性。只要有乙個不能保證,就有可能導致程式的執行錯誤 synchronized就能保障原子性,可見性,有序性,1.因為synchronized能保障任意乙個時刻只有乙個執行緒執行該 塊,自然就不存在原子性的問題 2.在釋放鎖之前會將變數的修改重新整理到主存中,因此保證可見性 3.又...

Java併發程式設計 JMM和volatile關鍵字

通過快取一致性協議 string s abc int i 0 i i 0 主記憶體 i 執行緒1 j i 執行緒22.被volatile關鍵字修飾變數不會指令重排序。public class novisibility private static class readthread extends t...