volatile 和 synchronized 的区别

1. 核心区别概述

特性volatilesynchronized
作用范围仅修饰变量修饰代码块或方法
原子性仅保证单次读/写原子性(如 long/double保证代码块/方法的原子性
可见性强制线程从主内存读取最新值保证进入同步块前刷新变量,退出后写回
有序性禁止指令重排序保证同步块内有序执行
阻塞性非阻塞(仅内存屏障)阻塞(线程竞争锁会挂起)
适用场景状态标志、一次性发布(如 DCL)复合操作(如 i++)、临界区保护
锁机制无锁,仅内存屏障基于 Monitor 锁(JVM 实现)
性能读操作接近普通变量,写稍慢较高开销(涉及线程阻塞/唤醒)

2. 详细对比

(1) 原子性

  • volatile

    • 仅保证单次读/写操作的原子性(如 volatile int x = 10 是原子的)。

    • 不保证复合操作的原子性(如 x++ 不是原子的,因为它包含 read-modify-write 三步)。

  • synchronized

    • 保证整个同步块的原子性(如 synchronized { x++; } 是原子的)。

示例:

// volatile 不能保证原子性
volatile int count = 0;
count++;  // 非原子操作(实际是 read + modify + write)

// synchronized 保证原子性
synchronized (this) {
    count++;  // 原子操作
}

(2) 可见性

  • volatile

    • 强制所有线程从主内存读取最新值,修改后立即写回主内存

    • 适用于状态标志(如 volatile boolean flag)。

  • synchronized

    • 进入同步块前,强制刷新工作内存(读取最新值)。

    • 退出同步块时,强制写回主内存

示例:

// volatile 保证可见性
volatile boolean running = true;

// synchronized 保证可见性
synchronized (lock) {
    if (condition) {
        // ...
    }
}

(3) 有序性(防止指令重排序)

  • volatile

    • 通过内存屏障禁止 JVM 和 CPU 对指令重排序。

    • 典型应用:DCL(双重检查锁)单例模式

  • synchronized

    • 同步块内的代码顺序执行,不会重排序。

示例(DCL 单例模式):

class Singleton {
    private static volatile Singleton instance;  // 防止指令重排

    public static Singleton getInstance() {
        if (instance == null) {  // 第一次检查(无锁优化)
            synchronized (Singleton.class) {
                if (instance == null) {  // 第二次检查(防止多线程多次创建)
                    instance = new Singleton();  // volatile 防止重排序
                }
            }
        }
        return instance;
    }
}

(4) 阻塞性

  • volatile

    • 非阻塞,仅通过内存屏障保证可见性和有序性。

    • 适合轻量级同步(如状态标志)。

  • synchronized

    • 阻塞,未获取锁的线程会进入 BLOCKED 状态。

    • 适合临界区保护(如计数器、共享资源访问)。


3. 如何选择?

场景推荐方案原因
单变量状态标志(如 booleanvolatile轻量级,无锁,性能高
复合操作(如 i++synchronized保证原子性
DCL 单例模式volatile + synchronized防止指令重排 + 原子性
复杂同步逻辑synchronized 或 ReentrantLock更灵活的控制

4. 总结

  • volatile 适用于单变量可见性防止指令重排(如 DCL 单例)。

  • synchronized 适用于复合操作临界区保护(如计数器、共享资源)。

  • volatile 不能替代 synchronized,它仅适用于特定场景。

回答示例:

"volatile 和 synchronized 都能保证可见性,但 synchronized 还能保证原子性和互斥访问。volatile 适用于状态标志等简单场景,而 synchronized 适用于需要原子操作的场景。例如,i++ 必须用 synchronized,而 boolean 标志可以用 volatile 优化性能。"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值