Java中volatile的作用以及用法
找了很多資料,包括《Java併發程式設計實戰》,綜合一下各家的說法就是:
volatile讓變數每次在使用的時候,都從主存中取。而不是從各個執行緒的“工作記憶體”。
volatile具有synchronized關鍵字的“可見性”,但是沒有synchronized關鍵字的“併發正確性”,也就是說不保證執行緒執行的有序性。
也就是說,volatile變數對於每次使用,執行緒都能得到當前volatile變數的最新值。但是volatile變數並不保證併發的正確性。
看下面的例子:
假如count變數是volatile的。執行緒1,執行緒2 在進行read,load 操作中,發現主記憶體中count的值都是5,那麼都會載入這個最新的值線上程1堆count進行修改之後,會write到主記憶體中,主記憶體中的count變數就會變為6,執行緒2由於已經進行read,load操作,在進行運算之後,也會更新主記憶體count的變數值為6,導致兩個執行緒及時用volatile關鍵字修改之後,還是會存在併發的情況。
--------------------------------------
綜合了查詢到的資料,上面的解釋,還算理解的過去。但是《java併發程式設計實戰》上的例子,就不是很明白了。
看下面
----------------------------------------------------------------
java併發程式設計實戰上說,如果變數不是volatile的,那麼在被其他執行緒修改之後,之前的執行緒是不會感知到的。但是下面的程式碼,asleep被修改了之後,其他四個執行緒卻都停止了輸出。不明白是怎麼回事。
- package comz;
- /**
-
* 這段程式碼雖然沒有volatile,但是另外的執行緒設定為true的時候,其他的四個執行緒依然停止了執行。 與書上不一致。為啥?
- * 書上說,如果不是volatile的,則另外的執行緒更新這個值的時候,其他的執行緒是不會感知到的。所以其他執行緒就不會停止執行。
- * @author naughty
- *
- */
- class T {
- publicstaticboolean asleep = false;
- publicstaticvoid main(String[] args) throws InterruptedException {
- for (int i = 0; i < 4; i++) {
-
new Thread(new Runnable() {
- @Override
- publicvoid run() {
- judge();
- }
- }).start();
- }
- Thread.sleep(3000);
- new Thread(new Runnable() {
- publicvoid run() {
- asleep = true;
- System.out.println("end");
- }
- }).start();
- }
- publicstaticvoid judge() {
- while (!asleep) {
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- CMS();
- }
- }
- publicstaticvoid CMS() {
- System.out.println("@");
- }
- }
----------------------------
那麼,我們這裡說執行緒要先拷貝變數到自己的工作記憶體,然後再使用。在這裡,什麼是執行緒的工作記憶體呢?
看看JLS(java語言規範)對執行緒工作記憶體的描述,執行緒的working memory只是cpu的暫存器和快取記憶體的抽象描述。