volatile关键字

volatile关键字

作用

  1. 保证变量内存可见性
  2. 禁止指令重排序
  3. 不保证原子性

可见性问题

用一段代码来验证可见性问题,当代码运行时,虽然i在主进程被置为1,但是子进程并没有退出,而是一直在循环。

public class Demo01 {
    public static int i  = 0;
    public static void main(String[] args) throws InterruptedException {
        new Thread(()->{
            while (i==0){
            }
        }).start();
        Thread.sleep(3000);
        i = 1;
        System.out.println("结束");
    }
}

这是由于JMM的原因,子进程从主存取到最新的i值,导致死循环无法退出。
在i变量中添加volatile关键字后,当i更新时,其它线程可以立刻看到被更新的值,因此加上volatile关键字后,子线程可以正常退出。

指令重排序问题

指令重排序是由于处理器为了提高执行效率而进行的不影响依赖关系情况下的重排序。体现在代码上就是在实际执行代码的时候,可能并不是以写的顺序来执行。
这种重排序在单线程时是没有问题的,但是在多线程同时对公共变量做操作时会出现问题。
volatile通过添加内存屏障的机制来避免指令重排序。
这里有一篇文章讲的比较详细

原子性问题

虽然解决了内存可见性问题,但是并没有解决原子性问题。
总结一下就是 对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种复合操作不具有原子性

public class Demo02 {
    private static volatile int num = 0;
    public static void main(String[] args) {
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                for (int i1 = 0; i1 < 1000; i1++) {
                    add();
                }
            }).start();
        }

        while (Thread.activeCount()>2){
            Thread.yield();
        }

        System.out.println(num);
    }

    public static void add(){
        num++;
    }
}
posted @ 2022-01-10 10:03  聚乙烯  阅读(62)  评论(0)    收藏  举报