1.背景
volatile 修飾的作用????
什麼是可見性??
什麼是指令重排序??
2.可見性-案例
package com.my.aqs; /** * @Copyright (C) XXXXX技有限公司 * @Author: ldp * @Date: 2023/4/28 9:10 * @Description: <p> * volatile 的可見性代碼演示 * </p> */ public class Volatile021Demo { // 如果a 沒有 被 volatile 修飾,這裏的a是 [不可見的] ,[不可以] 讀取到其他線下修改後的值, 即從[工作]內存中讀取==> 產生死循環 // 如果a 被 volatile 修飾,這裏的a是 [可見的] ,[可以]讀取到其他線下修改後的值, 即從[主]內存中讀取 ==> 不會產生死循環 // static volatile int a, b; static int a, b; /** * 指令重排序測試 * * @param args */ public static void main(String[] args) throws InterruptedException { // 線程A Thread threadA = new Thread(() -> { a = 1; System.out.println("A執行完成:" + a); }); // 線程B Thread threadB = new Thread(() -> { // 如果a 沒有 被 volatile 修飾,這裏的a是 [不可見的] ,[不可以] 讀取到其他線下修改後的值, 即從[工作]內存中讀取==> 產生死循環 // 如果a 被 volatile 修飾,這裏的a是 [可見的] ,[可以]讀取到其他線下修改後的值, 即從[主]內存中讀取 ==> 不會產生死循環 while (a == 0) { try { // System.out.println("等待中===="); // 就算不添加volatile 修飾a, 執行輸出語句後a會重新從主內存中讀取 // System.out.println("當前a==>:" + a); // Thread.sleep(500);// 就算不添加volatile 修飾a, 執行輸sleep後a會重新從主內存中讀取 b = a; // 不會導致從主內存中讀取 } catch (Exception e) { e.printStackTrace(); } } System.out.println("B執行完成:" + a); }); threadB.start(); // 讓B線程先執行 Thread.sleep(50); threadA.start(); while (threadA.isAlive() || threadB.isAlive()) { } System.out.println("main執行完成:" + a); } }
3.避免指令重排序-案例
package com.my.aqs; import java.util.HashSet; import java.util.Set; /** * @Copyright (C) XXXXX技有限公司 * @Author: ldp * @Date: 2023/4/28 15:03 * @Description: */ public class Volatile03Demo { // static volatile int a, b, A, B; static int a, b, c, d; /** * 指令重排序-案例演示 * <p> * 如果:下面的代碼,如果不考慮 指令重排序的問題, c和d永遠都不會同時爲0; * 但是:因爲在沒有volatile修飾的情況下,可能會產生指令重排序,因此會產生 指令重排序, * 導致 * t1線程中先執行 c = b; * t2線程中先執行 d = a; * 這兩行代碼先執行,從而導致c 和 d同時爲0; * * @param args * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { long num = 0; Set<String> ABSet = new HashSet<>(8); while (true) { num++; a = 0; b = 0; c = 0; d = 0; Thread t1 = new Thread(() -> { a = 1; c = b; }); Thread t2 = new Thread(() -> { b = 1; d = a; }); t1.start(); t2.start(); t1.join(); t2.join(); ABSet.add("a=" + a + "|b=" + b + "|c=" + c + "|d=" + d); if (c == 0 && d == 0) { System.out.println("a=" + a + "|b=" + b + "|c=" + c + "|d=" + d); System.out.println("num=" + num); System.out.println(ABSet); break; } } } }