初探併發程式設計(一)AtomicInteger、Volatile關鍵字、可重入鎖
1:為什麼要引入AtomicInteger關鍵字
在java中,多個執行緒訪問一個共享變數時會發生執行緒安全問題。
例子:
Count類:
主函式開三個執行緒:
我們希望count的值為599,但是由於是多執行緒,所以結果如下:
那麼我們應該怎麼處理呢?
java為我們引入了一個包(atomic)來處理該情況。
程式碼如下:
count類:
結果如下:
AtomicInteger關鍵字能保證變數值得準確性,但不能保證它們能按順序輸出。但一般我們都只是獲取它的值,而不是列印它的值。
如果你既想保證數字的準確性又想保證能按順序輸出,你只能用Synchronized關鍵字了
程式碼如下:
總結: synchronized關鍵字是一種內部鎖,可以理解成一個小黑屋,每個執行緒走到被synchronized程式碼塊包含的程式碼就像進入這個小黑屋,只能一個一個的操作。
2:volatile關鍵字
被volatile修飾的變數,在多個執行緒下是可見的,其作用是讓該變數在多哥執行緒下是透明的(讓程式從記憶體中載入,不允許在快取中載入)。可以保證變數的修改讓所有執行緒可見;
程式碼:
按我們所想,就倆執行緒不過怎麼著,程式總會停止吧。但是,程式死在這裡了。如圖
為什麼會這樣?
因為執行緒是CPU啟動的,而CPU一開始從主存中取資料並沒有立即將資料送到CPU,而是先送到了快取中, 另外一個執行緒修改bChanged的值,是就該主存中的值,而那個輸出結果的執行緒並沒有從主存中取bChanged的值,而是去快取中取了bChanged的值,而快取中bChanged的值是false,這就是為什麼會死迴圈的原因。如下圖
這個時候,java提供的volatile關鍵字就派上了用處。它保證了變數線上程之間的可見性。讓程式不要去快取中取值,而是去主存中取值。
你會發現加上volatile關鍵字後,程式會秒停。
3:可重入鎖
一個執行緒獲取它本身的鎖是可以成功的,多個執行緒同時搶佔同一個鎖會失敗。因為他們之間是互斥的。但是一個執行緒再次獲取一個自己已經拿過的鎖是可以成功的,這叫可重入鎖機制 。