深入理解Java Volatile關鍵字

2021-07-25 17:35:57 字數 1620 閱讀 8696

1.volatile關鍵字的作用是什麼?

a.當乙個變數被定義為volatile之後,它將具備兩種特性:

一:保證此變數對所有執行緒的可見性

可見性的意思為:當某個執行緒對volatile變數的值進行了修改,其他的執行緒是可以立即得知的;而普通的變數是無法做到這一點的,執行緒先是對工作記憶體當中的普通變數副本進行修改,再將變數的值在主記憶體當中進行重新整理,對工作記憶體修改完成而沒來得及同步到主記憶體中的這段時間內,其他執行緒將會讀到過期的值,造成執行緒不同步;而volatile定義的變數可以認為工作記憶體與主記憶體達成某種協議,工作記憶體中volatile變數值的改變會被立即重新整理到主記憶體中(稍後還會詳細論述),因此被volatile修飾的變數可以認為是具有記憶體可見性的;(但這並不能完全保證執行緒安全)

public class demo 

} } public static void main(string args)

//等待所有的執行緒結束,再列印出k的值

while(thread.activecount()>1)

system.out.println(k);

}}

如圖所示**:一共建立了20個執行緒,每個執行緒都會對k自加1000次,如果執行緒同步的話,那麼輸出的k值應該是20000,但是實際輸出的值確永遠是小於20000的,執行緒並不同步。

原因是:在進行變數k++操作的時候,k值的變化是依賴於它本身的,自加操作並不是原子性的操作;k++就是k=k+1;而加法是通過資料結構棧來實現的,執行k=k+1操作,計算機執行的實k1+,是先把變數k  push()進棧,再將1  push()進棧,遇到+號,執行k+1,再將k+1的值賦給k,就是說在你將k push()到棧裡面,但是操作還未完成的過程的這段時間內,其他執行緒有可能讀取了還未改變的k值,或對k值進行了改變,因而造成執行緒不同步;

二:禁止指令重排序優化

首先弄清楚什麼是指令重排序:cpu採用了允許將多條語句指令不按程式規定的順序分開發送給各個相應的電路單元處理;當然,並不是隨便亂重排的,cpu需要能夠正確處理指令點之間的依賴關係,保障程式能得出正確的結果;對指令的分別執行速度必定會大於嚴格按照指令的順序,單一電路單元的處理速度更快;

禁止指令重排序:在對volatile變數賦值的過程中,會加入乙個「記憶體屏障」,不能把這個屏障後面的指令重排序到屏障之前;

那指令重排序是如何干擾程式執行的呢?看下面的示例:

volatile  boolean  flag=false;

//初始化引數的執行緒(a)

config con=new config();

(1) con.setxx("xx");

(2) con.setyy("yy");

//再通知其他的執行緒初始化完畢,可以執行後面的操作

(3) flag=true;

//後續工作的執行緒,依賴於初始化執行緒(b)

while(!flag)

(4) dosomething(config);

程式的本意是等執行緒a初始化完畢之後再執行執行緒b,但是因為指令重排序的存在,指令(3)的執行順序有可能在指令(1)或者(2)之前就執行完畢了,這樣就會導致config物件還沒有初識化完成就執行了指令(4)的操作,可能會導致指令(4)無法正常執行,加入volatile則可以避免這種情況;

深入理解C語言 深入理解指標

關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...

mysql 索引深入理解 深入理解MySql的索引

為什麼索引能提高查詢速度 先從 mysql的基本儲存結構說起 mysql的基本儲存結構是頁 記錄都存在頁裡邊 各個資料頁可以組成乙個雙向鍊錶每個資料頁中的記錄又可以組成乙個單向鍊錶 每個資料頁都會為儲存在它裡邊兒的記錄生成乙個頁目錄,在通過主鍵查詢某條記錄的時候可以在頁目錄中使用二分法快速定位到對應...

深入理解C語言 深入理解指標

關於指標,其是c語言的重點,c語言學的好壞,其實就是指標學的好壞。其實指標並不複雜,學習指標,要正確的理解指標。指標也是一種變數,占有記憶體空間,用來儲存記憶體位址 指標就是告訴編譯器,開闢4個位元組的儲存空間 32位系統 無論是幾級指標都是一樣的 p操作記憶體 在指標宣告時,號表示所宣告的變數為指...