• Java volatile 关键字


    参考

    介绍

    volatile 关键字保证变量的内存可见性,禁止指令重排序, 不保证原子性

    内存可见性

    内存可见性是指当一个线程修改了某个变量的值,其它线程总是能知道这个变量变化。也就是说,如果线程 A 修改了共享变量 V 的值,那么线程 B 在使用 V 的值时,能立即读到 V 的最新值。

    禁止指令重排序

    为了提高性能,在遵守 as-if-serial 语义(即不管怎么重排序,单线程下程序的执行结果不能被改变。编译器,runtime 和处理器都必须遵守。)的情况下,编译器和处理器常常会对指令做重排序。使用 volatile 修饰变量时,根据 volatile 重排序规则表,Java 编译器在生成字节码时,会在指令序列中插入内存屏障指令来禁止特定类型的处理器重排序。内存屏障是一组处理器指令,它的作用是禁止指令重排序和解决内存可见性的问题。

    代码

    不安全的测试

    package future;
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * @Author 夏秋初
     * @Date 2022/3/4 16:01
     */
    public class Test1 {
    
        public static int num;
    
        public static void main(String[] args){
            for (int i = 0; i < 10; i++) {
                new Thread(() -> {
                    try {
                        TimeUnit.SECONDS.sleep(3);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    for (int j = 0; j < 10; j++) {
                        num++;
                    }
                }, String.valueOf(i)).start();
            }
            /**
             * 等待只剩 main 与 gc 线程才进行下一步
             */
            while (Thread.activeCount() > 2) {
    
            }
            System.out.println(num);
    
        }
    }
    
    

    线程安全的测试

    不使用锁及synchronized

    package future;
    
    
    import java.util.concurrent.TimeUnit;
    import java.util.concurrent.atomic.AtomicInteger;
    
    /**
     * @Author 夏秋初
     * @Date 2022/3/4 14:19
     */
    public class Test {
        /**
         * volatile 只是保证可见性,并不能保证原子性
         * AtomicInteger 是 juc 提供的无锁工具包 Integer 工具类,通过调用 jni 本地接口方法实现。
         */
        public static volatile AtomicInteger num = new AtomicInteger();
        public static  void main(String[] args) throws InterruptedException {
            for (int i = 0; i < 10; i++) {
                new Thread(()->{
                    try {
                        TimeUnit.SECONDS.sleep(3);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    for (int j = 0; j < 10; j++) {
                        num.getAndIncrement();
                    }
                }, String.valueOf(i)).start();
            }
            /**
             * 等待只剩 main 与 gc 线程才进行下一步
             */
            while (Thread.activeCount() > 2){
    
            }
            System.out.println(num);
    
        }
    }
    
    

    可见性测试

    System.out.println("当前 A status 的值为"+ status); 可以获取最新的 A status,但是 A 线程的 while 获取不到最新的值并且还在运行

    package future;
    
    import java.util.concurrent.TimeUnit;
    
    /**
     * @Author 夏秋初
     * @Date 2022/3/4 16:03
     */
    public class Test2 {
        /**
         * 可见性测试
         */
        public static Boolean status = true;
        public static volatile Boolean vstatus = true;
        public static void main(String[] args) throws InterruptedException {
            new Thread(()->{
                while (status){
    
                }
                System.out.println("A执行完毕");
            },"A").start();
            new Thread(()->{
                while (vstatus){
    
                }
                System.out.println("B执行完毕");
                System.out.println("当前 A status 的值为"+ status);
            },"B").start();
    
            TimeUnit.SECONDS.sleep(3);
    
            status  = false;
            vstatus = false;
        }
    }
    
    
  • 相关阅读:
    LIGGGHTS中的restart命令
    paraview计算面上的流量
    paraview计算面上的平均压力
    paraview计算区域中的平均流速
    paraview提取非常好看的流线图
    paraview显示颗粒的快捷方法
    paraview显示网格很多线条重合问题
    CFDEM中writeLiggghtsProps命令
    paraview使用ExtractCellsByRegion提取球阀阀芯中的颗粒数量
    Paraview 显示模拟时间
  • 原文地址:https://www.cnblogs.com/xiaqiuchu/p/15964970.html
Copyright © 2020-2023  润新知