一、简短结论
- CAS是基础:所有Java锁机制的底层都依赖CAS实现原子操作
- AQS是框架:ReentrantLock等JUC锁基于AQS,AQS使用CAS+CLH队列
- synchronized是混合锁:经历了偏向锁→轻量级锁→重量级锁的升级过程,内部大量使用CAS
- 锁选择原则:简单场景用synchronized,需要高级功能用ReentrantLock
二、详细内容
1. CAS(Compare And Swap)
定义:无锁算法的核心,原子性地比较并更新值
实现原理:
// 伪代码booleanCAS(Vexpect,Vupdate){if(currentValue==expect){currentValue=update;returntrue;}returnfalse;}Java实现:
sun.misc.Unsafe类的compareAndSwapInt/Long/Object- JUC包中的Atomic类:
AtomicInteger、AtomicReference等
特点:
- 乐观锁思想
- 通过自旋(循环尝试)实现
- 解决ABA问题:使用
AtomicStampedReference(带版本号)
2. AQS(AbstractQueuedSynchronizer)
作用:JUC并发包的基石框架
核心组成:
state:同步状态变量(volatile)- CLH队列:双向链表存储等待线程
- Node节点:包含线程、等待状态、前后指针
ReentrantLock与AQS关系:
- 公平锁/非公平锁都是AQS子类
state=0表示锁空闲,state>0表示被持有- 可重入:
state记录重入次数
AQS的CAS使用:
// 状态更新protectedfinalbooleancompareAndSetState(intexpect,intupdate){returnunsafe.compareAndSwapInt(this,stateOffset,expect,update);}// 队列操作(入队、设置头尾节点)都用CAS保证线程安全3. synchronized锁升级过程
Java对象头Mark Word结构(64位):
| 锁状态 | 54位 | 2位 | 1位(偏向) | 2位(锁标志) | |----------|----------------------|------|-----------|-------------| | 无锁 | hashCode/分代年龄等 | | 0 | 01 | | 偏向锁 | ThreadID(54位) | | 1 | 01 | | 轻量级锁 | 指向栈中锁记录的指针 | | | 00 | | 重量级锁 | 指向Monitor的指针 | | | 10 | | GC标记 | 空 | | | 11 |锁升级流程:
偏向锁(单线程访问)
- 首次进入:CAS设置ThreadID到Mark Word
- 重入:检查ThreadID匹配直接进入
轻量级锁(轻度竞争)
- 有竞争时撤销偏向锁
- 创建锁记录(Lock Record)复制Mark Word
- CAS将对象头指向锁记录
- 失败则自旋尝试
重量级锁(重度竞争)
- 自旋超过阈值(默认10次)
- 膨胀为重量级锁,向OS申请互斥量
- 线程进入等待队列,涉及内核态切换
synchronized中的CAS应用:
- 偏向锁获取/撤销
- 轻量级锁的锁记录设置
- 锁升级的状态转换
4. synchronized vs ReentrantLock
synchronized:
- JVM内置,自动管理锁获取/释放
- 非公平锁(但内部有优化)
- 只有一个条件队列(wait/notify)
- 优化后性能接近ReentrantLock
ReentrantLock:
- JDK实现,基于AQS
- 手动lock/unlock(需finally释放)
- 可中断、可超时、可公平
- 支持多个Condition
- 提供
tryLock非阻塞获取
使用选择:
- 简单同步:synchronized(简洁不易出错)
- 复杂需求:ReentrantLock(灵活控制)
5. 关键问题答案
Q1:AQS内部使用CAS还是什么?
- 主要使用CAS:更新state、入队出队、设置头尾节点都依赖CAS
- 配合volatile:state用volatile保证可见性
- park/unpark:线程阻塞/唤醒机制
Q2:synchronized的实现原理?
- 混合锁实现:偏向锁+CAS+轻量级锁+重量级锁
- 锁升级策略:根据竞争强度动态升级
- CAS关键作用:锁状态转换、线程ID设置、锁记录操作
6. 锁优化建议
- 减少锁粒度:锁尽量小的代码块
- 减少锁持有时间:尽快释放锁
- 读写分离:读多写少用读写锁
- 无锁化:能用CAS就不用锁
- 避免锁嵌套:预防死锁
7. 现代优化趋势
- 偏向锁废弃(Java 15+):维护成本高,实际收益有限
- 自适应自旋:根据历史成功率动态调整自旋次数
- 锁消除:JIT编译器移除不可能竞争的锁
- 锁粗化:合并连续的小锁为一个大锁
总结:Java锁机制从底层CAS到高层AQS再到synchronized,形成完整的并发控制体系。理解这些原理有助于写出高效、正确的并发代码,也能更好地排查并发问题。