首頁>技術>

Java併發程式設計之volatile

上一篇文章中我們介紹了 Synchronzied ,接下來我們來介紹 volatile。

我們知道 Java 記憶體模型有三大特性,有序性、可見性、原子性。

我們首先來談一談有序性。

那麼什麼是有序性呢?Talk is cheap,show me the code 我們直接來看程式碼。

public static void main(String[] args) { int num1=10;//程式碼1 int num2=5;//程式碼2 num1=num1-num2;//程式碼3 num2=num1*num1;//程式碼4 }複製程式碼

這段程式碼的執行順序一定是程式碼1、2、3、4 嗎?這是不一定的,為什麼呢?因為可能會發生指令重排序。指令重排序就是在不影響程式最終結果的前提下,為了提升程式的執行效率,可能會對輸入的程式碼順序進行優化,造成執行順序不一定按照程式碼書寫順序的一種形式。

我們來看看指令重排序的定義,一個必要的條件就是不影響程式的執行結果,那麼想想看我們的程式碼3和程式碼4的執行順序能否調換順序呢?答案自然是否定的,因為程式碼4需要依賴程式碼3的內容。

在單執行緒的情況下,重排序不會影響程式的執行結果,那麼在多執行緒情況下呢?我們來看一看。

//執行緒1:context = loadContext(); //語句1inited = true; //語句2//執行緒2:while(!inited ){ sleep()}doSomethingwithconfig(context);複製程式碼

首先線上程1中先執行語句2,然後切換到執行緒2來執行。這個時候執行緒二認為初始化已經完成,就會進行接下來的操作,但是 context 並沒有初始化,所以就會導致程式碼出錯。

接下來是可見性

可見性是指當一個執行緒修改了共享變數後,其他執行緒能夠立即得知這個修改。

我們使用 volatile 關鍵字可以保證可見性,使得各個執行緒都可以讀取到最新的值

最後是原子性

原子性是指一個操作是不可中斷的,要麼全部執行成功要麼全部執行失敗,有著“同生共死”的感覺。及時在多個執行緒一起執行的時候,一個操作一旦開始,就不會被其他執行緒所幹擾。

我們來看一個最簡單的例子,程式碼 i++ 是原子性操作嗎?其實 i++ 可以分為3步來看待。

讀取 i 值對 i +1把新值賦給 i

這其中任何一步發生都可能發生執行緒安全問題,所以 i ++ 不是原子性操作。

介紹完我們的三大特性,我們回過頭再來說 volatile , volatile 關鍵字可以做到可見性和有序性。也就是可以保證變數獲取最新的值以及禁止指令重排序,但是它不能實現原子性,所以 volatile 的使用具有侷限性,我們簡單地來總結一下它的使用場景。

對變數的寫入操作不依賴當前的值,或者你能確定只有單個執行緒能夠更新變數的值該變數不會和其他狀態變數一起納入不變性條件中在訪問變數時不需要加鎖

37

Java

  • BSA-TRITC(10mg/ml) TRITC-BSA 牛血清白蛋白改性標記羅丹明
  • SQLite 3.30.0 釋出 世界上使用量最大的資料庫引擎