volatile關鍵字使用總結

volatile關鍵字使用總結java

VikingBird 發表於2個月前緩存

   

原volatile關鍵字使用總結多線程

 收藏app

VikingBirdide

 

  • 發表於 2個月前
  •  
  • 閱讀 20
  •  
  • 收藏 0
  •  
  • 點贊 0
  •  
  • 評論 0

騰訊雲·雲上實驗室:開發者零門檻,無償使用真機在線實驗!>>>   測試

摘要: 本文主要總結了volatile關鍵字的使用this

什麼是volatile關鍵字

volatile 關鍵字在多線程程序中起着很重要的做用。當多個線程操做同一個變量時,每一個線程將擁有對那個變量的本地緩存拷貝,所以,當某一個線程修改了這個變量的值時,實際上修改的是它本地緩存中的變量值,而不是主內存中的變量值,操做這個變量的其餘線程並不知道這個變量的值被改變了。爲了不這種狀況,咱們能夠用 valatile 關鍵字聲明這個變量,用 valatile 聲明瞭這個變量以後,變量將不在本地緩存中保存,而在主內存中保存,當有線程修改了它的值之後,它的更新值將被更新到主內存當中,隨後,其餘線程也能訪問更新後的值。當一個變量被聲明爲 volatile 後,java 內存模型確保全部使用該變量的線程能看到相同的、一致的值。spa

volatile關鍵字使用

首先,建立 VolatileData 類,代碼以下:.net

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 關鍵字時,咱們必須注意如下幾點:

  • volatile 關鍵字並不能消除原子之間的同步操做的須要,由於內存一致性錯誤仍然是可能的

  • 使用原子變量比使用 synchronized 同步代碼更有效率,可是爲了不內存一致性錯誤,須要做出額外的努力

  • volatile 關鍵字不能替代 synchronized 同步代碼塊和方法

相關文章
相關標籤/搜索