volatile重要特性-可見性,避免指令重排序-案例講解

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;
            }
        }
    }
}

 

完美!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章