Java volatile 关键字的 用法

96 阅读2分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

1、什么是可见性?

可见性是指线程A改变变量的值后,线程B可以马上看到更改后变量的值

2、volatile的作用

关键字volatile提示线程每次从共享内存中读取数据,而不是从私有内存中读取,这样就保证了同步数据的可见性

3、volatile适用的场景

当想实现一个线程对一个变量进行修改,希望其他线程可以取到最新的值的时候。就需要对变量使用volatile关键字了

4、实战

import static java.lang.Thread.sleep;

public class VolatileTest {
    public static boolean flag  = true;

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程1 开始!");
                while(flag){

                }
                System.out.println("线程1 结束!");
            }
        });

        Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程2 开始!");
                flag = false;
                System.out.println("flag = " + flag);
            }
        });

        t1.start();
        sleep(2000);
        t2.start();

    }
}

运行结果:

image.png

我们可以看到:程序在一直运行,进入了死循环,那么是什么原因造成出现了死循环呢?

我么在启动线程t1之后,变量“public static boolean flag = true;”存在于公共堆栈及线程私有的堆栈中,t1运行后一直在线程私有堆栈中取得的flag的值是true,而线程2的代码“flag = false;”,修改的是公共堆栈中的flag,所以t1线程私有堆栈中的flag仍然是true。

解决方式: 添加volatile关键字

public static volatile boolean flag = true;

image.png

5、volatile是否具有原子性?

关键字volatile最大的缺点是不支持原子性,如果修改实例中的数据,比如i++,这样的操作不是原子操作,分为三步

  • 从内存中取i的值
  • 计算i的值
  • 将i的值存入内存中 如果在第二步计算i的值时,其他线程读取i的值,并对i进行修改,这个时候就会出现脏数据,解决方法是使用synchronized关键字