volatile /synchronized/ Lock 如何保证 可见性、有序性、原子性

一、先记住 3 大特性是什么

  1. 可见性:一个线程改了变量,其他线程能立刻看到最新值
  2. 有序性:禁止 CPU 指令重排,代码按顺序执行
  3. 原子性:操作不可被打断,要么全部完成,要么不做

 

二、三者能力总表(直接背)

 
关键字可见性有序性原子性
volatile ✅ 保证 ✅ 保证 不保证
synchronized ✅ 保证 ✅ 保证 ✅ 保证
Lock (ReentrantLock) ✅ 保证 ✅ 保证 ✅ 保证
 

 

三、分别讲清楚:它们怎么保证的?

1. volatile 如何保证? 

① 可见性

  • 写 volatile 变量时,直接把工作内存刷新到主内存
  • 读 volatile 变量时,直接从主内存重新读取
  • 不使用副本,保证最新

② 有序性 

  • 加了 内存屏障(Memory Barrier)
  • 禁止 CPU 指令重排
  • 前面的代码不能跑到 volatile 后面,后面不能跑到前面

③ 为什么不保证原子性?

因为像 i++ 这种操作是 读 → 改 → 写 三步
volatile 只能保证每一步可见,但不能保证三步不被打断
 

 

2. synchronized 如何保证?

① 可见性

  • 解锁时,所有修改都会强制刷新回主内存
  • 加锁时,会重新从主内存加载最新变量

② 有序性

  • 加锁区域内的代码,具有 Happens-Before 规则
  • 指令重排不会跨越锁区域
  • 保证有序

③ 原子性

  • 同一时刻只有一个线程能拿到锁
  • 临界区代码完全独占,不可被中断
  • 完美保证原子性

 

3. Lock(ReentrantLock)如何保证?

和 synchronized 原理几乎一样,但基于 AQS + volatile 实现

① 可见性

  • lock () 时:从主内存读最新
  • unlock () 时:强制刷新到主内存

② 有序性

  • 内部使用 volatile 状态 + 内存屏障
  • 禁止重排,保证有序

③ 原子性

  • 同一时间只有一个线程能获取锁
  • 临界区独占,保证原子性

 

四、最经典一句话总结(面试必背)

  • volatile可见性 + 有序性 ✅ ,原子性 ❌
  • synchronized可见性 + 有序性 + 原子性 全能 ✅
  • Lock和 synchronized 一样全能 ✅,更灵活

 

五、最简单记忆口诀

  • volatile 管看不管改(可见、有序,不保证原子)
  • synchronized 全能但重
  • Lock 全能更灵活
 
posted @ 2026-03-05 15:22  小兵要进步  阅读(4)  评论(0)    收藏  举报