1. 程式人生 > >初探併發程式設計(一)AtomicInteger、Volatile關鍵字、可重入鎖

初探併發程式設計(一)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:可重入鎖

一個執行緒獲取它本身的鎖是可以成功的,多個執行緒同時搶佔同一個鎖會失敗。因為他們之間是互斥的。但是一個執行緒再次獲取一個自己已經拿過的鎖是可以成功的,這叫可重入鎖機制 。