阐述 volatile 和 synchronized 的区别以及底层原理

volatile 和 synchronized 的区别

1 核心定位

  1. volatile变量修饰符,只保证可见性、禁止指令重排,不保证原子性
  2. synchronized :同步锁,保证可见性 + 禁止重排 + 原子性(互斥),可以修饰方法、代码块

2 多维度对比

特性 volatile synchronized
原子性 ❌ 不保证,复合操作(i++)不安全 ✅ 保证,同一时刻只有一个线程执行
可见性 ✅ 强制刷新主存,变量修改立刻对其他线程可见 ✅ 锁释放时刷新主存,也保证可见性
有序性(指令重排序) ✅ 禁止重排序 ✅ 锁块内禁止越界重排序
作用对象 只能修饰成员变量 修饰方法 / 代码块,作用于对象锁
阻塞 不会阻塞线程 会阻塞,竞争不到锁线程等待
性能 开销很小,无锁 开销大,涉及锁竞争、内核态切换
适用场景 读多写少,状态标记位 多线程读写、计数、复合操作

2.1 volatile

重点:不保证原子性

i++ 分为三步:读i → +1 → 写回

volatile只能保证读到最新值,不能把三步打包成原子,多线程下依然会出现计数错误。

java 复制代码
volatile int i = 0;
i++; // 线程不安全!

volatile典型使用场景:状态开关标记

java 复制代码
volatile boolean stop = false;
//线程1
while(!stop){ ... }
//线程2修改stop=true,其他线程立刻感知

2.2 synchronized

  • 底层:对象监视器monitor,加锁、解锁。
  • 加锁:获取monitor,清空本地缓存,从主存读取变量。
  • 释放锁:把本地缓存修改刷新回主存。
  • 锁把整个代码块变成原子,多线程不会交错执行。
java 复制代码
synchronized (obj){
    i++; // 线程安全
}

3 底层原理简述

  1. volatile :内存屏障(memory barrier)

    写volatile后插入写屏障,强制把CPU缓存数据刷回主内存(内存条RAM);读volatile前插入读屏障,强制从主内存读取,阻止CPU指令重排。不加锁。

  2. synchronized :monitor锁

    偏向锁→轻量级锁(CAS)→重量级锁(操作系统互斥锁),有锁升级过程。既做互斥,又通过内存屏障保证可见性与重排序。

4 总结

volatile 是轻量级的,只解决可见性、禁止重排,不能保证原子性,适合布尔标记;
synchronized 是锁,原子、可见、防重排全包,会阻塞,适合复合读写操作。

5 常见坑

  1. 不要用volatile做计数器 i++,结果错乱。
  2. volatile不能修饰局部变量。
  3. synchronized不仅加互斥锁,同样自带可见性,不需要再搭配volatile。
相关推荐
要开心吖ZSH12 天前
本地缓存方案选择指南:volatile、ConcurrentHashMap、Caffeine 怎么选?
缓存·caffeine·volatile·本地缓存
Tsuki_tl13 天前
【面试高频】 HashMap, HashTable,ConcurrentHashMap 之间的区别
面试·hashmap·synchronized·哈希表·多线程并发·hashtable·分段锁
j7~1 个月前
【Linux】二十二.《Linux 信号机制完全指南:表示、捕捉与处理》
linux·信号处理·volatile·可入重函数·保存信号
ComputerInBook1 个月前
C & C++ 中的关键字 volatile 之详解
c语言·c++·volatile·编译器优化
折哥的程序人生 · 物流技术专研1 个月前
《Java 100 天进阶之路》第53篇:volatile与JMM(2026版)
java·volatile·内存屏障·可见性·java内存模型·jmm·java100天进阶
rebibabo2 个月前
Java高并发底层原理(七)volatile 到底解决了什么问题
java·学习笔记·volatile·可见性·有序性·指令重排
Trouvaille ~3 个月前
【Redis篇】Redis 事务:原子性与脚本执行机制
数据库·redis·后端·算法·junit·lua·原子性
fengxin_rou3 个月前
【JUC第二章下】:锁机制&关键字
架构·事务·cas·juc·volatile
Tsuki_tl3 个月前
【面试高频】常见锁策略
多线程·synchronized·八股文·java面试·锁机制·悲观锁·java后端面试