What is volatile?

What is volatile?

一次偶然的機會(java多線程電梯做業尋求多個進程分享變量的方法),接觸到了volatile,所以我查閱了相關的材料,對這部分作了一些瞭解,在這裏和你們分享一下。java

首先,咱們先來聊一聊幾個概念編程

一、What is reorder

編譯器和JVM經過改變程序的處理順序來優化程序,用於提升程序性能的方式。緩存

多線程程序設計中,重排序會致使運行錯誤。多線程

舉個栗子:性能

class Compare {
   private int x = 0;
   private int y = 0;
   
   public void write() {
       x = 100;
       y = 50;
  }
   
   public boolean compare() {
       return x<y
  }
}

public class Main {
   public static void main(String[] args) {
       final Compare com = new Compare();
       new Thread() {
           public void run() {
               com.write();
          }
      }.start();
       new Thread() {
           public void run() {
               com.read();
          }
      }.start();
  }
}

讓人吃驚的是,x<y竟然真的存在true的狀況優化

緣由就在於重排序this

編譯器的優化策略可能會改變x,y的賦值順序,致使x<yatom

顯然,咱們能夠經過synchronized來解決這個問題spa

二、What is visibility

線程A將某個值寫入字段x,線程B讀到了這個值線程

多線程中的可見性問題來源於normal read/write操做是經過緩存在執行的,read到的不必定是最新值,write的也不必定當即對其餘線程可見

而synchronized是解決這一問題的有效方法,相信你們也並不陌生,具體用法能夠參考個人另外一篇博客

其實,volatile也是一種不錯的方法

 

三、What is atomicity

不可分割的操做,例如某線程正在執行synchronized方法,其餘線程沒法進入該方法,從多線程的角度,這就是原子操做。

Java定義了一些原子操做:primitive type(char、int)的賦值和引用,對象等引用類型的賦值和引用

可是long與double的操做不是原子的,在線程共享時須要放入synchronized

 

now,進入正題

Volatile

Make sure that a given variable is read directly from main memory and always written back to main memory when updated

volatile具備同步處理(參考sunchronization)和對long和double的原子操做這兩種功能

同步處理

一、若是線程A向volatile字段寫入的值對線程B可見,那麼以前向其餘字段寫入的值都是對B可見

二、向volatile字段讀取和寫入先後不會發生重排序

看到這裏,咱們發現重排序和可見性的問題好像都被volatile解決了

在這裏,咱們來看一段代碼,深刻理解一下同步處理

class TryVolatile {
   private int num = 0;
   private volatile boolean valid = false;
   
   public void write() {
       num = 1;
       valid = true;
       /*
        *一、不會被重排序
        *二、線程B中valid會爲true
        *三、線程B可能出現num=1
        */
  }
   
   public void read() {
       if (valid) {
           System.out.println(this.num);
      }
  }
}

public class Main {
   public static void main(String[] args) {
       final tryVolatile = new TryVolatile;
       new Thread() {
           public void run() {
               tryVolatile.write();
          }
      }.start();
       new Thread() {
           public void run() {
               tryVolatie.read();
          }
      }.start();
  }
}

總結一下volatile的使用:

一、volatile字段賦值語句位置很重要!!!(能夠運行上面的代碼觀察

二、volatile不會進行線程互斥處理(volatile字段不會進入等待隊列

三、訪問volatile字段會產生性能開銷(參考synchronized

 

對long和double的原子操做

tip:

java.util.concurrent.atomic包提供了原子操做編程的類,例如AtomicInteger、AtomicLong、AtomicIntegerArray等,都是經過封裝volatile獲得的

相關文章
相關標籤/搜索