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