JAVA中synchronized 和 volatile 的区别

1. synchronized(同步锁)

  • 核心作用
    提供 ‌原子性(Atomicity)‌ 和 ‌可见性(Visibility)‌ 的双重保障。
  • 工作原理
    • 通过获取对象的 ‌内置锁(Monitor Lock)‌,确保同一时刻只有一个线程能执行同步代码块或方法。
    • 在锁释放时,强制将线程本地内存的修改刷新到主内存(保证可见性)。
  • 特性
    • 原子性‌:保护代码块或方法的执行不可分割。
    • 互斥性‌:同一时间仅允许一个线程访问资源。
    • 可重入性‌:线程可以重复获取自己持有的锁。
  • 适用场景
    需要保证多个操作的原子性(如共享变量的复合操作 i++)或复杂代码块的线程安全。

示例‌:

public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++; // 原子操作
    }
}

2. volatile(易变变量)

  • 核心作用
    仅保证变量的 ‌可见性‌ 和 ‌禁止指令重排序‌,不提供原子性。
  • 工作原理
    • 通过强制线程直接从主内存读写变量,绕过本地缓存。
    • 通过内存屏障(Memory Barrier)禁止编译器或 CPU 对指令重排序。
  • 特性
    • 可见性‌:变量的修改对所有线程立即可见。
    • 有序性‌:禁止指令重排序优化(遵循 Happens-Before 规则)。
  • 适用场景
    单一变量的读写操作,且不依赖当前值的复合操作(如状态标志位)。

示例‌:

public class StatusChecker {
    private volatile boolean running = true;

    public void stop() {
        running = false; // 其他线程立即可见
    }
}

3. 关键区别

特性synchronizedvolatile
原子性✅ 保证代码块或方法的原子性❌ 不保证原子性
可见性✅ 通过锁释放刷新主内存✅ 直接读写主内存
有序性✅ 同步块内的代码有序执行✅ 禁止指令重排序
互斥性✅ 同一时间仅一个线程访问❌ 允许多线程并发读写
性能影响高(涉及锁竞争和上下文切换)低(无锁机制)
适用范围复杂逻辑或多步操作的同步单一变量的可见性控制

4. 典型使用场景

  • synchronized
    • 复合操作(如 i++check-then-act)。
    • 需要互斥访问共享资源(如文件写入、数据库连接池)。
  • volatile
    • 状态标志位(如 boolean running)。
    • 单次写入、多次读取的变量(如配置参数)。

5. 注意事项

  • volatile 的局限性
    即使变量是 volatile,类似 count++ 的操作仍是非原子的,需结合 AtomicInteger 或 synchronized
  • synchronized 的优化
    JDK 1.6 后引入锁消除、锁粗化、偏向锁等优化,降低性能开销。

总结

  • 需要 ‌原子性‌ 或 ‌互斥访问‌ → 用 synchronized
  • 只需 ‌可见性‌ 或 ‌禁止重排序‌ → 用 volatile
    两者可结合使用(如用 volatile 状态标志控制同步块的执行)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时光呢

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值