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

 

完美!

posted @ 2023-04-28 16:23  李东平|一线码农  阅读(18)  评论(0编辑  收藏  举报