Java并發(fā)volatile可見性的驗證實現(xiàn)
普通讀 無法及時獲得 主內(nèi)存變量
public class volatileTest { static boolean flag = false;//非volatile變量 public static void main(String[] args) throws Exception { new Thread(new Runnable() { @Override public void run() { while(!flag){ }; } }).start(); Thread.sleep(100); flag = true; System.out.println("主線程運行完畢"); } }
主線程已經(jīng)修改了flag為true,但子線程一直不會退出循環(huán),因為子線程一直沒有同步到 主內(nèi)存中的變量的值。
截圖可見程序一直沒有退出,使用dump threads后:
"Thread-0" #12 prio=5 os_prio=0 tid=0x0000000022d89800 nid=0x168 runnable [0x00000000248df000]
java.lang.Thread.State: RUNNABLE
at volatileTest$1.run(volatileTest.java:10)
at java.lang.Thread.run(Thread.java:745)
volatile讀 及時獲得 主內(nèi)存變量
public class volatileTest { static volatile boolean flag = false;//volatile變量 public static void main(String[] args) throws Exception { new Thread(new Runnable() { @Override public void run() { while(!flag){ }; } }).start(); Thread.sleep(100); flag = true; System.out.println("主線程運行完畢"); } }
加了一個volatile關(guān)鍵字,子線程就能檢測到flag的變化了。子線程會退出。
普通讀+sleep
public class volatileTest { static boolean flag = false;//非volatile變量 public static void main(String[] args) throws Exception { new Thread(new Runnable() { @Override public void run() { while(!flag){ try { Thread.sleep(1); } catch (InterruptedException e) { e.printStackTrace(); } }; } }).start(); Thread.sleep(100); flag = true; System.out.println("主線程運行完畢"); } }
加了sleep,子線程會退出。
其實就算變量不是volatile的,JVM也會盡量去保證可見性。最開始的例子,由于CPU一直執(zhí)行循環(huán),沒有其他時間來獲取 主內(nèi)存中的變量的最新值,但加了sleep后,CPU就有時間去獲取 主內(nèi)存中的東西了。
普通讀+同步塊
public class volatileTest { static boolean flag = false;//非volatile變量 static Object sync = new Object(); public static void main(String[] args) throws Exception { new Thread(new Runnable() { @Override public void run() { while(!flag){ synchronized (sync) {}//隨便synchronized一個對象 //synchronized (this)也可以 }; } }).start(); Thread.sleep(100); flag = true; System.out.println("主線程運行完畢"); } }
加了同步塊,子線程會退出。
這是因為synchronized具體過程是:
- 獲得同步鎖;
- 清空工作內(nèi)存;
- 從主內(nèi)存拷貝對象副本到工作內(nèi)存;
- 執(zhí)行代碼(計算或者輸出等);
- 刷新主內(nèi)存數(shù)據(jù);
- 釋放同步鎖。
簡單的說,synchronized進入時,會將 主內(nèi)存中最新的變量,拷貝進 自己線程 的工作內(nèi)存。synchronized退出時,會把 自己線程的工作內(nèi)存的變量 弄進 主內(nèi)存中。
同步塊 遭遇 鎖消除
public class volatileTest { static boolean flag = false;//非volatile變量 public static void main(String[] args) throws Exception { new Thread(new Runnable() { @Override public void run() { while(!flag){ synchronized (new Object()){} }; } }).start(); Thread.sleep(100); flag = true; System.out.println("主線程運行完畢"); } }
子線程不會退出。
原因是:synchronized (new Object()){}
中這個Object永遠不可能逃逸到同步塊以外去,所以同步操作其實根本不需要執(zhí)行了,既然沒有執(zhí)行同步,那么相當于這里是啥也沒有。
普通讀+System.out.println
public class volatileTest { static boolean flag = false; public static void main(String[] args) throws Exception { new Thread(new Runnable() { @Override public void run() { while(!flag){ System.out.println("子線程running"); }; } }).start(); Thread.sleep(100); flag = true; System.out.println("主線程運行完畢"); } }
加了System.out.println
,子線程會退出。
因為out這個PrintStream實例的println實現(xiàn)是:
public void println(String x) { synchronized (this) { print(x); newLine(); } }
因為它也有同步塊。
到此這篇關(guān)于Java并發(fā)volatile可見性的驗證實現(xiàn)的文章就介紹到這了,更多相關(guān)Java并發(fā)volatile驗證內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot整合WebSocket的客戶端和服務(wù)端的實現(xiàn)代碼
這篇文章主要介紹了SpringBoot整合WebSocket的客戶端和服務(wù)端的實現(xiàn),本文通過實例代碼給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2022-07-07使用Spring的攔截器監(jiān)測每個Controller或方法的執(zhí)行時長
這篇文章主要介紹了使用Spring的攔截器監(jiān)測每個Controller或方法的執(zhí)行時長,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-10-10使用@DS輕松解決動態(tài)數(shù)據(jù)源的問題
這篇文章主要介紹了使用@DS輕松解決動態(tài)數(shù)據(jù)源的問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-05-05