小米是一名 Java 开发工程师,工作五年,最近正准备跳槽。作为一个有追求的程序员,怎么能不去大厂试试呢?
这天,他兴冲冲地来到了某互联网大厂的面试现场。面试官是个戴着黑框眼镜的资深架构师,简历翻了几页后,微微一笑,开口问道:
“小米,能不能和我聊聊 Java 的 volatile 关键字?你在实际工作中用过它吗?”
小米心里咯噔一下,volatile 这个东西倒是听过,可是……实践?他脑子里迅速回忆起几年前看的 JMM(Java 内存模型)相关的文章,以及自己踩过的坑,清了清嗓子,开始了他的回答。
volatile 是个啥?小米微笑着说:“volatile 是 Java 里一个轻量级的同步机制,它的主要作用是保证可见性和防止指令重排。”
面试官点点头,示意他继续。
“我最开始接触 volatile 这个关键字,是在处理多线程变量可见性问题的时候。”小米回忆道,“有一次,我写了一个简单的标志位,线程 A 负责更新,线程 B 负责读取,结果发现 B 线程一直拿不到 A 线程的最新值。”
他随手写下了当时的代码:
“这段代码你觉得有什么问题?”小米抬头看向面试官。
可见性问题与 volatile 的解法“问题就在于 stop 变量没有使用 volatile 修饰!”小米继续说道,“在多线程环境下,线程 B 可能永远看不到线程 A 修改 stop 的值。”
为什么会这样?
因为 Java 内存模型(JMM)中,每个线程都有自己的工作内存(线程本地缓存),如果一个变量没有被 volatile 修饰,线程 B 可能一直使用自己缓存的 stop,而不是去主内存获取最新值。
但是加上 volatile 之后,stop 的值修改后会立即刷新到主内存,线程 B 读取时也必须去主内存拿最新的值,保证了变量的可见性。
小米快速修改代码,加上 volatile:
有了 volatile,线程 A 修改 stop,线程 B 就能立刻感知到变化,不会死循环了!
面试官点点头,继续问道:“那除了可见性,还有什么用?”
volatile 能防止指令重排小米沉思了一下,说:“还有一个重要作用,就是防止指令重排。”
他继续解释道:
指令重排是 JVM 和 CPU 为了优化程序执行速度,会动态调整指令执行顺序,但这可能导致多线程环境下的代码乱序执行。
举个例子,比如在双重检查锁(DCL)中,volatile 主要用来防止指令重排。
如果不加 volatile,可能出现这样的问题:
线程 A 进入 getInstance() 方法,发现 instance == null,准备创建实例。
关键一步:instance = new Singleton(); 这行代码可以被 CPU 重排序为:
分配内存
赋值给 instance(但此时构造方法还未执行完)
执行构造方法
假设此时线程 B 也调用 getInstance(),它看到 instance != null,直接返回这个还没完全初始化的实例,就会导致空指针异常。
加上 volatile,可以防止这个指令重排问题,确保 new Singleton() 的顺序是严格按照分配内存 -> 执行构造方法 -> 赋值的顺序进行。
面试官露出了一丝满意的笑容:“不错,你在实际项目中遇到过这个问题吗?”
volatile 的实践场景小米点点头:“有,在我们公司,一个订单系统里用到了 volatile。”
他们有一个订单处理系统,某个变量 orderProcessed 需要在多个线程之间共享,保证一个线程修改了它,其他线程能立刻看到变化。
他写出了当时的代码:
这里 volatile 主要确保多个线程能及时看到 orderProcessed 变量的变化,避免多个线程重复处理同一个订单。
volatile 不能做什么?“不过 volatile 也有局限性。”小米继续补充道,“它不能保证原子性。”
比如 i++ 这种操作,即使加上 volatile 也不能保证线程安全。
这里 count++ 实际上是三个步骤:
读取 count 的值
计算 count + 1
赋值回 count
在多线程环境下,多个线程可能同时读取同一个 count,导致数据覆盖。解决办法是用 AtomicInteger 或 synchronized。
总结:volatile 用于啥?小米整理了一下思路,总结道:
适用场景:
变量可见性问题
防止指令重排(比如 DCL)
状态标志位
不适用场景:
不能保证原子性(i++ 仍然需要 AtomicInteger 或 synchronized)
END面试官听完,微微一笑:“回答不错,你有实际经验,也能深入理解 volatile 的作用。这轮面试通过了!”
小米松了口气,暗暗给自己比了个大拇指。
希望这篇文章能帮到你,下次面试遇到 volatile,你也能自信作答!
我是小米,一个喜欢分享技术的31岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货!