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

posted @ 2022-03-04 16:37  夏秋初  阅读(150)  评论(0编辑  收藏  举报