菜鸡每日一面系列打卡14天
每天一道面试题目
助力小伙伴轻松拿offer
坚持就是胜利,我们一起努力!
题目描述
谈谈你对volatile关键字的理解。
题目分析
在Java面试中,尤其是有关多线程方面知识的考查,volatile关键字只会迟到,不会缺席。对volatile关键字的理解,不仅是对多线程编程实践的考查,更要求对程序执行过程和原理的把握。volatile是JVM提供的最轻量级的同步机制,但由于其不容易被正确、完整的理解,在实际工作中,很多程序员都会绕道而行。因此,在面试过程中也很容易载跟头。不仅如此,全面了解volatile关键字,对理解多线程操作很有帮助。接下来,随菜鸡一起去看看吧。
题目解答
开宗明义,volatile关键字的作用主要有两个:可见性与禁止指令重排序优化。但仅仅这样回答显然不能满足面试官的要求,还需要阐述个人理解和一些细节上的说明。
-
可见性,保证被volatile关键字修饰的变量(以下简称volatile变量)对所有线程可见。从逻辑上看,volatile变量对所有线程是立即可见的,也就是说,对volatile变量的写操作会立刻反映到其他线程当中。
为什么强调是从逻辑上看呢?因为,从物理存储角度看,各个线程的工作内存中volatile变量可以不一致,但每次使用之前都会进行刷新,因此,逻辑上是一致的。volatile的特殊规则保证了新值能立即同步到主内存,并且store和write操作是连续的,每次使用前立即从主内存刷新,并且read和load操作是连续的。
但这并不意味着,使用volatile变量能保证线程安全。众所周知(其实也不一定),Java中的运算操作符并非原子操作,因此,volatile变量的运算并不是线程安全的。最常见的例子便是形如i++的自增运算。
public class IncreaseTest {
public static volatile int i = 0;
// 非线程安全,因为自增运算不是原子操作
public static void increase() {
i++;
}
}
-
禁止指令重排序优化,防止机器级别的指令重排序优化造成并发编程中的错误。什么是指令重排序呢?指令重排序就是处理器在保证程序能得出正确的执行结果的前提下,允许指令执行顺序的改变。这是基于优化提高效率的考虑。而在并发编程情况下,这种优化很容易是自作聪明的表现,导致一系列难以排查的问题。在《深入理解Java虚拟机》一书中,周志明老师用单例懒汉式实现的汇编代码进行了举例,说明了volatile关键字通过在指令中添加内存屏障的方式禁止了指令重排序,菜鸡在这里要说明两点:
-
-
加volatile关键字主要是为了在instance变量被初始化为Singleton实例时,避免指令重排序导致的多线程不能正确处理instance变量,而由第一条可知,由于volatile的可见性,在instance变量初始化完成之后,立刻反映到其他线程当中,也就可以一定程度上避免新加入的线程对锁的竞争。
-
-
-
书中对于单例的懒汉式实现出现了一些小失误,并未给出私有的构造方法,菜鸡对这段代码进行了补全如下。
-
public class Singleton {
private volatile static Singleton instance;
// 私有构造方法
private Singleton() {}
public static Singleton getInstance() {
if (instance == null) {
synchronized (Singleton.class) {
if (instance == null) {
instance = new Singleton();
}
}
}
return instance;
}
}
以上便是菜鸡关于volatile关键字的一些理解,供大家参考。
学习 | 工作 | 分享
长按关注“有理想的菜鸡”
只有你想不到,没有你学不到