首頁  >  文章  >  Java  >  Java中關於volatile關鍵字的使用與注意事項

Java中關於volatile關鍵字的使用與注意事項

黄舟
黄舟原創
2017-07-30 10:14:401551瀏覽

這篇文章主要介紹了java volatile關鍵字使用方法及注意事項的相關資料,當一個變量被聲明為volatile 後,java 內存模型確保所有使用該變量的線程能看到相同的、一致的值。 ,需要的朋友可以參考下

java volatile關鍵字使用方法及注意事項

什麼是volatile關鍵字

#volatile 關鍵字在多執行緒程式中扮演著很重要的角色。當多個執行緒操作同一個變數時,每個執行緒將擁有對那個變數的本地快取拷貝,因此,當某一個執行緒修改了這個變數的值時,實際上修改的是它本地快取中的變數值,而不是主記憶體中的變數值,操作這個變數的其他執行緒並不知道這個變數的值被改變了。為了避免這種情況,我們可以用valatile 關鍵字聲明這個變量,用valatile 聲明了這個變量之後,變量將不在本地緩存中保存,而在主內存中保存,當有線程修改了它的值以後,它的更新值將會更新到主記憶體當中,隨後,其他執行緒也能存取更新後的值。當一個變數被宣告為 volatile 後,java 記憶體模型確保所有使用該變數的執行緒都能看到相同的、一致的值。

volatile關鍵字使用

首先,建立VolatileData 類,程式碼如下:

public class VolatileData {

  //声明为volatile类型
  private volatile int counter = 0;

  /**
  * 返回counter变量的值
  * @return
  */
  public int getCounter() {
    return counter;
  }

  /**
  * 自增counter变量的值
  */
  public void increaseCounter() {
    ++counter;
  }
}

接下來創建VolatileThread 類,程式碼如下:

public class VolatileThread extends Thread {
  private final VolatileData volatileData;

  public VolatileThread(VolatileData volatileData) {
    this.volatileData = volatileData;
  }

  /**
  * 调用VolatileData类中的两个方法,进行取值和自增操作
  */
  @Override
  public void run() {
    int oldValue = volatileData.getCounter();
    System.out.println("[Thread " + Thread.currentThread().getId() + "]: Old value = " + oldValue);
    volatileData.increaseCounter();
    int newValue = volatileData.getCounter();
    System.out.println("[Thread " + Thread.currentThread().getId() + "]: New value = " + newValue);
  }
 }

最後,建立VolatileMain 類,對上述程式進行測試,程式碼如下:

#
public class VolatileMain {

  private final static int TOTAL_THREADS = 2;

  public static void main(String[] args) throws InterruptedException {
    VolatileData volatileData = new VolatileData();

    Thread[] threads = new Thread[TOTAL_THREADS];
    for(int i = 0; i < TOTAL_THREADS; ++i)
      threads[i] = new VolatileThread(volatileData);

    //开始读取变量值的操作
    for(int i = 0; i < TOTAL_THREADS; ++i)
      threads[i].start();

    //等待所有线程操作终止
    for(int i = 0; i < TOTAL_THREADS; ++i)
      threads[i].join();
  }
}

在VolatileMain 類別中,使用了兩個執行緒來存取volatile 變量,輸出如下:

[Thread 10]: Old value = 0
[Thread 11]: Old value = 0
[Thread 10]: New value = 1
[Thread 11]: New value = 2

從輸出可以看到,首先,兩個執行緒都輸出了相同的值,接著,在increaseCounter 方法被呼叫之後,兩個執行緒都存取和輸出了最新的volatile 變數的值。

happens-before 關係式

在使用 volatile 關鍵字時,我必須提及 java 記憶體模型的 happens-before 關係。 happens-before 關係是 java 記憶體模型的重要面向。它建立在兩個不同的事件之間,使第一個事件對物件的所有改變都可以被第二個事件看到和反映。例如當一個執行緒對 volatile 變數進行寫入操作後,另一個執行緒隨後存取該變量,happens-before 關係就建立了。因此,所有對 volatile 變數的改變對其他執行緒來說都是可見的。

需要注意的

    當程式中使用volatile 關鍵字時,我們必須注意以下幾點:
  1. volatile 關鍵字並不能消除原子之間的同步操作的需要,因為記憶體一致性錯誤仍然是可能的
  2. 使用原子變數比使用synchronized 同步程式碼更有效率,但是為了避免記憶體一致性錯誤,需要做出額外的努力
  3. volatile 關鍵字不能取代synchronized 同步程式碼區塊和方法
#######

以上是Java中關於volatile關鍵字的使用與注意事項的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn