java编程,如何彻底理解volatile关键字?

黄元中


volatile在Java语言中扮演者重要的角色,它具有可见性以及禁止指令重排序两个非常显著的特点,要想解释清楚volatile的用法,首先我们要对Java的内存模型JMM有一个非常熟悉的了解,所以我从以下几点来分析volatile。

一、Java内存模型JMM

Java的内存模型规定:所有的变量都保存在主内存中,每一个线程都有属于自己的工作内存,当读取主内存的变量时,线程的工作内存都会都会存储这个变量的副本,线程对变量的操作都是在自己的工作内存中,在适当的时候会把自己工作内存的变量同步到主内存中。

从上面的内容中可以得出一个结论,多线程对变量的修改,都是先修改自己的工作内存的变量,然后把工作内存中修改的在适当的时候同步到主内存中,那么问题就来了,适当的时候是什么时候呢?不确定,所以就有问题了,当主内存中有一个变量i=0,假如同时有两个线程去修改i的值,当线程1读取主内存中的i=1,然后拷贝一份副本在自己的工作内存中,然后i=1,但是这是操作的自己的工作内存i=1,但是这个i=1什么时候刷新到主内存中呢?刚才我们说了,不确定,此时线程二读取主存的变量i=0,然后也拷贝一份到自己的工作内存中,然后i=2,然后在适当的时候刷新到主存中,所以最终的结果可能是线程二i=2的结果先刷新到主存中,线程一i=1最后刷新到主存中,这就导致现在主存中i=1,所以与想象的结果不一样。

二、volatile的大白话

了解了Java的内存模型JMM,我们了解了对于一个共享变量,如果有多个线程并发的修改这个共享变量,最终得到的结果可能与我们想象的不太一样,这是由于JMM的机制导致的,而这和我们所说的volatile有什么关系的,那接下来我们就说说。

结论:1:如果一个变量被volatile修饰,那么它在工作内存中修改的变量会立刻被刷新到主存中。而不是上面所说的不确定的时候

2:如果读取一个被volatile修饰的变量,会把此线程工作内存中的此变量副本置为无效,它会从主内存中重新读取这个变量到自己的工作内存。

上面这两点分别是volatile写内存语义和volatile内存语义。

三、volatile在JDK的使用

在JDK中,并发包中volatile把它的特点发挥到了极致,尤其通过框架AQS的state就是被volatile修饰的,在加上CAS构建出了无锁化的同步框架,在ConcurrentHashMap中也是因为有了volatile的作用加上CAS操作提高了很大的性能。

上面3点只是简单的说明了volatile的作用,如果要详细介绍volatile,估计能够一本上百页的书了,在这里就不再详述了,如果想进一步了解volatile,请关注我的头条,我会有一个关于volatile的专题。


强哥Java架构之路


非java程序员,不过volatile在其他语言中也存在,简单说下。

1,volatile只在多线程程序中有意义。

2,为了提高性能,编译器工作时会进行一些优化,如指令排序,甚至跳过一些指令。如:

var a=1;

a=2;

a=3;

编译后的结果可能就只执行 a = 3

3,程序运行时,普通变量会有缓存机制(如cpu缓存、线程本地缓存等),程序读取时先从缓存读取,所以多线程的程序运行时可能存在脏读问题。即第一个线程已经修改了变量值,但第二个线程还在使用缓存中的旧数据。

volatile的作用就是告诉编译器,不要对使用该变量的代码进行优化,每次读写操作都访问变量的原始数据。


xdm99


通常程序不会直接去操作CPU内核线程,而是通过内核线程的接口轻量级进程(LWP)来操作的,也就是通常意义上的线程.


系统在执行多线程任务时,数据存储在RAM中,然而每个线程都有一个本地缓存,也就是CPU缓存,并不会每次都从RAM读取数据,所以就会出现线程不安全的情况。

Java中volatile关键字主要是用来修饰变量使其能够被线程可见.


飞升的码农


https://m.toutiaocdn.com/group/6682538998579069453/?app=news_article×tamp=1556016557&req_id=201904231849160100160441948694FA8&group_id=6682538998579069453

参考这篇文章


huJeson


建议先学习java内存模型以及指令重排序,如此就能真正理解


分享到:


相關文章: