码迷,mamicode.com
首页 > 其他好文 > 详细

关于volatile关键字

时间:2019-12-22 00:16:12      阅读:109      评论:0      收藏:0      [点我收藏+]

标签:blank   关键字   修饰符   bool   sch   执行   ace   rup   方法   

来源:衡阳网站优化 

  在java核心卷1中对volatile关键字是这么描述的:

volatile关键字为实例域的同步访问提供了一种免锁机制。如果声明一个域为volatile,那么编译器和虚拟机就知道该域是可能被另一个线程并发更新的。

    上述解释可以通过下面代码直观的描述:

public class VolatileAtomicSample {
    static Logger logger = Logger.getLogger(VolatileAtomicSample.class);

    private static boolean initFlag = false;

    public static void refresh() {
        logger.info("refresh data ......");
        initFlag = true;
        logger.info("refresh data success ......");
    }

    public static void loadData() {
        while (!initFlag) {

        }
        logger.info("线程:" + Thread.currentThread().getName()
                + "当前线程嗅探到initFlag的状态的改变!");
    }

    public static void main(String[] args) {
        Thread threadA = new Thread(VolatileAtomicSample::loadData,"threadA");
        threadA.start();
        try {
            Thread.sleep(500);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        Thread threadB = new Thread(() -> {
            refresh();
        }, "threadB");
        threadB.start();
    }

上面的代码中线程B执行了refresh方法,貌似initFlag的值被改成了true,但是执行的结果仍然是:

refresh data ......

refresh data success ......

并没有打印:线程:threadA当前线程嗅探到initFlag的状态的改变!

如果将变量initFlag 用关键字 volatile 修饰,那么结果就是:

19/12/21 20:58:15 INFO volatile1.VolatileAtomicSample: refresh data ......
19/12/21 20:58:15 INFO volatile1.VolatileAtomicSample: refresh data success ......
19/12/21 20:58:15 INFO volatile1.VolatileAtomicSample: 线程:threadA当前线程嗅探到initFlag的状态的改变!

那么volatile的工作原理是什么,在底层是如何执行的。

可以通过一个图来描述:

技术图片

 

主内存简称“主存” ,工作内存可以叫做线程的缓存。

线程A将initFlag先read出来,然后load到线程A的缓存中去,然后use就是交给代码来使用。

线程B也按线程A的方式来使用initFlag。

但是线程A,B之间是没有可见性的。所以,线程A读出来的initFlag=flase,是在线程A的工作内存中操作,线程B读出来的initFlag是在线程B的工作内存中操作,也是initFlag=flase,就算线程B将initFlag重新赋值成true,线程A也不知道,就出现了第一个结果。

    如果将initFlag加上一个volatile修饰符,那么线程B的中将initFlag的值改成true,就会执行assign,将true从代码部分放回线程B的工作内存,然后线程B的工作内存回执行store,然后再将修改的数据write到主存中去,这个时候,各个线程回对总线做监听,这个总线可以理解成一条河,那么所有线程都从总线中知道initFlag的状态发生改变了。然后每个对initFlag操作的工作线程都停止自己的操作,重新从主存中获取最新的数据再操作。

所以就是下面的这个图:

技术图片

 

volatile 的工作原理就是上面的样子。

画外音:图确实画的有点渣。

 

关于volatile关键字

标签:blank   关键字   修饰符   bool   sch   执行   ace   rup   方法   

原文地址:https://www.cnblogs.com/1994july/p/12078753.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!