volatile是java虛擬機提供的輕量級的同步機制 JMM(Java記憶體模型)是圍繞著併發編程中原子性、可見性、有序性這三個特征來建立的 原子性:一個操作或多個操作要麼全部執行完成且執行過程不被中斷,要麼就不執行。 可見性:當多個線程同時訪問同一個變數時,一個線程修改了這個變數的值,其他線程能夠 ...
volatile是java虛擬機提供的輕量級的同步機制
JMM(Java記憶體模型)是圍繞著併發編程中原子性、可見性、有序性這三個特征來建立的
原子性:一個操作或多個操作要麼全部執行完成且執行過程不被中斷,要麼就不執行。
可見性:當多個線程同時訪問同一個變數時,一個線程修改了這個變數的值,其他線程能夠立即看得到修改的值。
有序性:程式執行的順序按照代碼的先後順序執行。
volatile保證了可見性,有序性,不保證原子性
證明可見性的代碼:
1 package concurrent; 2 3 import java.util.concurrent.TimeUnit; 4 5 /* 6 * @description: volatile特性 7 * @date 2019.04.22 20:48 8 */ 9 //數據類 10 class Mydata{ 11 12 volatile int num = 0; 13 14 public void changeNum(){ 15 this.num = 100; 16 } 17 } 18 19 public class VolatileDemo { 20 21 public static void main(String[] args) throws InterruptedException{ 22 Mydata mydata = new Mydata(); 23 new Thread(() -> { 24 System.out.println("===="+Thread.currentThread().getName() +"線程啟動==="); 25 //暫停3秒 26 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {} 27 //3秒後t1線程改變num的值 28 mydata.changeNum(); 29 System.out.println(Thread.currentThread().getName()+"線程將num的值改為"+mydata.num); 30 },"t1").start(); 31 32 //num的值不變就一直迴圈 33 long begin = System.currentTimeMillis(); 34 while (mydata.num == 0){ 35 //num如果不被volatile修飾會一直迴圈 36 } 37 long cost = System.currentTimeMillis() - begin; 38 System.out.printf(Thread.currentThread().getName()+"線程檢測到num的值已經改變,cost{%d},證明瞭volatile的可見性",cost); 39 } 40 }
運行結果為:
====t1線程啟動=== t1線程將num的值改為100 main線程檢測到num的值已經改變,cost{3001},證明瞭volatile的可見性
證明不保證原子性的代碼:
class Mydata{ volatile int num = 0; public void changeNum(){ this.num = 100; } public void numIncreOne(){ this.num++; } } public class VolatileDemo { public static void main(String[] args) throws InterruptedException{ Mydata mydata = new Mydata(); //開啟10個線程每個線程調用1000次num++ for (int i = 0; i < 10; i++) { new Thread(() -> { for (int j = 0; j < 1000; j++) { mydata.numIncreOne(); } },String.valueOf(i)).start(); } //輸出num的值,如果volatile能保證原子性num將等於10000 System.out.println(mydata.num); System.out.println(mydata.num ==10000?"volatile可以保證原子性":"volatile無法保證原子性"); } }
輸出結果:
5856
volatile無法保證原子性
多線程環境中,線程交替執行,編譯器會通過對指定進行重排序來進行優化。被volatile修飾的變數不會參與重排序,保證有序性。
證明有序性的代碼:
1 int num = 0; 2 3 private boolean flag = false; 4 5 private void reSort1(){ 6 num = 1; //語句1 7 flag = true; //語句2 8 } 9 10 private void reSort2(){ 11 if(flag){ 12 num++; 13 System.out.println("num的值為"+num); 14 } 15 }
多線程情況下有可能先執行語句2,再執行語句1,從而導致num只自增1次,輸出為1。