You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java并发中volatile何时必须使用?示例Result类value是否需volatile修饰?

Java多线程volatile相关问题解答

1. Java开发中必须为变量添加volatile关键字修饰的场景

volatile关键字的核心作用是保证变量的线程可见性、禁止指令重排序,但不保证操作的原子性,以下场景必须使用volatile修饰:

  • 多线程共享的状态标记量:比如用于控制线程启停的isShutdown这类布尔标记,这类变量通常只会被一个线程赋值、其他线程只读,没有锁交互,不加volatile会导致修改不能及时被其他线程感知,线程无法按照预期停止。
  • 双重检查锁(DCL)实现的单例模式:如果单例变量不加volatile,指令重排序可能会把对象初始化的指令重排到赋值操作之后,导致其他线程拿到还没完成初始化的半实例对象,引发空指针等异常。
  • 读多写少的低开销同步场景:如果变量的写操作本身是原子操作(比如直接给基础类型/引用赋值,不是i++这类复合操作),且读操作频率远高于写,用volatile替代锁可以大幅降低同步开销,同时保证读操作总能拿到最新值。

2. 示例代码中Result类的value变量不需要加volatile修饰

原因如下:

  • 首先Java内存模型对synchronized有明确的happens-before规则:线程解锁前对变量的修改,会全部同步回主内存;线程加锁后读取变量,会直接从主内存拉取最新值,保证可见性。代码中对value的所有写操作、以及同步块内的二次空校验读操作,都被synchronized(result)块包裹,已经由同步锁保证了可见性和有序性。
  • 你可能会注意到Task1、Task2中第一个if (result.getValue() == null)判断是在同步块外执行的,这个场景就算读到了本地缓存的旧值也不会影响正确性:就算首次判断误读到null,进入同步块后还有第二次空校验,第二次校验一定能拿到主内存的最新值,最多只是多执行了一次获取锁的逻辑,不会出现并发安全问题。
  • 主线程最后调用result.getValue()之前,已经执行完包含wait()的同步块,wait()返回时会重新获取锁,退出同步块时已经同步了主内存的最新值,所以也不会读到旧值。

内容的提问来源于stack exchange,提问作者Allme

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 11:24:05