一个人在这,虔诚的想你
java 小册子这一系列的每篇文章都会在开头提出一个面试的常见问题,大家可以当作日常的积累,每天都看一看。各位读者可以先尝试回答下,笔者也会给出自己的回答,读者也可以参考一下笔者的答案,如果觉得笔者的回答对你有帮助,可以自己积累一下;如果对笔者的回答有疑问,欢迎在评论区中给出自己的见解。
volatile 关键字是啥?
你在我这停了这么久,那就别怪我喜欢你了
首先说下在回答 volatile 关键字时可以吹的点:
- java 并发编程中三个重要的特性
- java 内存模型
- volatile 关键字的作用
- 正确的使用方式
接下来笔者会针对上面的四个点逐一的进行解答,话不多说,发车!!!
java 并发编程中三个重要的特性
大家都知道,java 是一门支持多线程的语言,说起多线程也就要提到并发,并发绝壁是 java 中的金字招牌。招牌那怎么能没有自己的特点呢(各位男宾应该都能理解这句话,点的多了,自己也可以总结下)?java 的并发特性就三个:原子性、有序性、可见性。笔者在这简单解释下:所谓原子就是指的执行过程不能被打断,可以结合数据库事务的原子性理解(要能打断,这多影响心情啊);有序指的是各个操作发生的先后顺序。(这里的先后指的并不一定是时间上的先后,这点需要结合可见性和重排序去理解);可见性指的是某个线程的操作结果能够被后续的线程观察到。现在的计算机为了追求极致的性能,编译器和处理器会对没有数据依赖性的指令进行重排序,因此在没有正确编写多线程的程序中,会因为指令重排序出现一些无法预测的问题。此时 JMM 就应运而生了。
人间忽晚,山河已秋
java 内存模型(JMM)
其实这也不是啥很高深的东西,大家平时在写代码时,肯定都用到过局部变量和全局变量吧。局部变量和今天讨论的主题不能说毫无关系,只能说毫不相干。而全局变量就不一样了,它可以被多个线程宠幸,能读还能写。在现如今的法制社会中,干啥都得讲规范,在计算机中同样不例外。JMM 就是这样一种规范:定义了线程间该如何通信与同步以及如何对主存中的全局变量进行读写。线程在操作全局变量时并不是大家想象的直接对其进行操作,而是先要将其读到自己的一块内存中,修改后再写回主存中,而且每个线程也只认主存中的东东。从这也可以看出,java 线程之间的通信是隐式进行的,每个线程通过在自己的内存中修改全局变量的值并写到主存中来告诉其他线程,我到底做了些啥。那么是不是我写回了,你就一定能看见呢?no!JMM 针对如何看见以及何时看见提出了 volatile 这个关键字。
volatile 关键字的作用
volatile 关键字可以实现上面提到的有序性及可见性。说简单点,就是某个线程修改了某个由 volatile 修饰的变量后,其他线程能第一时间看见;不仅如此,volatile 关键字还通过内存屏障这种机器指令来告诉编译器和处理器,你别费劲给我安排位置了,俺不需要!如果大家对 synchronized 关键字有过了解,其实可以发现对一个 volatile 变量的读操作就类似于加锁操作,总是读取最新的;而对一个 volatile 变量的写操作就类似于释放锁操作,将修改刷新回主存中。因此 volatile 关键字也被认为是一种多线程间轻量级的同步机制。
正确的使用方式
知道了是啥,接下来就是该了解应如何正确的使用了。volatile 关键字对一些复合操作是没办法保证有序性和可见性的,比如常见的 i++ 这类操作;也没办法像 synchronized 关键字那样可以让多个线程串行化执行某段代码。volatile 关键字比较适合用在标记变量上,比如某个标记值用于标记项目环境是否初始化完成,此时就可以使用 volatile 关键字,当初始化完成后,其他线程能够第一时间读取到并完成后续的工作;volatile 还可以用在单例模式中,单例模式中有一种经常被问的实现方式就是 DCL(双重校验锁),volatile 可以避免重排序导致其他线程读到一个尚未初始化完全的对象;volatile 也是作为 juc 的基石,帮助程序员更方便的编写正确的多线程程序。
昨晚没见到你,所以月亮缺了一块
以上就是本篇文章的全部内容了,如果有读者对文章内容有不同的见解,欢迎在评论区中提出,大家一起讨论、交流和学习。如果有读者从事的是工业互联网或者是制造业数字化转型的工作,也欢迎私信笔者,笔者在这方面很感兴趣哦!