Java多线程锁策略 笔记(通俗易懂+例子)
这三组是不同维度对锁的分类!不要混在一起:
- 悲观锁 / 乐观锁:思想层面(认为会不会发生并发冲突)
- 重量级锁 / 轻量级锁:synchronized底层实现层面(JVM里对象头的锁状态)
- 挂起等待锁 / 自旋锁:等待锁失败时的行为(拿不到锁怎么办)
一、悲观锁 VS 乐观锁
1. 悲观锁
想法:默认一定会发生并发冲突,每次操作数据,先上锁保护。只要操作共享数据,先把锁拿到手,别人无法修改。等我操作完释放锁,其他人才能访问。 ✅ 典型例子:synchronized、ReentrantLock、数据库select ... for update
生活例子:去卫生间,进门直接反锁。默认认为一定会有人跟我抢位置。
特点:
- 冲突多的时候,性能更好
- 会阻塞其他线程,拿不到锁就等待
2. 乐观锁
想法:默认不会发生并发冲突,不加锁;提交修改的时候,检查有没有被别人改动过。不上锁,直接读写;更新时校验版本号。如果数据已经被别人改了,本次修改失败,重试。 ✅ 典型例子:volatile + CAS(AtomicInteger)、数据库版本号version机制
生活例子:图书馆自习座位,不锁门;当你要坐下前,看一眼座位有没有被占。被占了就换位置重试。
特点:
- 冲突少的时候,性能高
- 没有阻塞,失败就重试;冲突特别多的时候,会不断重试,CPU浪费严重
一句话区分:悲观锁先锁再干活;乐观锁先干活,提交时检查冲突。
二、重量级锁 VS 轻量级锁(特指synchronized底层)
这两个都是悲观锁,是JVM对
synchronized的优化,存储在对象头Mark Word。
1. 重量级锁
依赖操作系统内核的互斥锁。 线程拿不到锁 →操作系统把线程挂起,放到内核等待队列;锁释放后,操作系统再唤醒线程。缺点:线程挂起(阻塞)、唤醒,需要用户态↔内核态切换,开销很大。
例子:多个线程长时间竞争同一个
synchronized锁,锁升级成重量级锁。
2. 轻量级锁
用户态实现,不调用操作系统内核锁。 适用场景:多个线程交替使用锁,几乎不并发竞争。 拿锁失败,不会直接挂起,而是尝试自旋。
注意:一旦出现两条线程同时抢锁,轻量级锁就膨胀升级为重量级锁。
一句话区分: 重量级锁:找OS内核帮忙,线程挂起唤醒,开销大。 轻量级锁:JVM在用户态处理,不依赖OS内核,适合低竞争场景。
补充:偏向锁(synchronized最底层优化):偏向锁是轻量级锁的前置状态,只有一个线程使用锁,连CAS操作都尽量省略。
三、挂起等待锁 VS 自旋锁(拿不到锁时的两种等待方式)
1. 挂起等待锁(阻塞锁)
抢锁失败:线程被操作系统挂起,休眠,让出CPU。 锁释放之后,操作系统再唤醒这个线程。 ✅优点:不占用CPU,线程休眠,CPU可以跑别的任务 ❌缺点:唤醒线程开销大,用户态内核态切换。
例子:synchronized重量级锁、ReentrantLock(默认非公平锁底层等待队列就是挂起等待)
2. 自旋锁
抢锁失败:不放弃CPU,循环不断重试抢锁(while循环),不停检查锁是否释放。
// 简易自旋锁伪代码 while (!尝试获取锁()) { // 原地循环,反复尝试抢锁 }✅优点:如果锁很快释放,不需要线程切换,速度快 ❌缺点:如果锁长时间拿不到,会一直循环,空耗CPU
例子:CAS实现的自旋锁、Atomic类底层就是自旋
生活例子: 挂起等待锁:排队办业务,拿号之后坐到椅子上休息,轮到你才叫你。(不占用柜台资源,但是叫号有延迟) 自旋锁:站在窗口前,不停反复问“好了没有?好了没有?”,一直循环询问,不离开。(短时间内很快,长时间就很累)
汇总表格(背诵版)
| 分类维度 | 锁 | 核心思想 | 典型示例 |
|---|---|---|---|
| 并发冲突预判 | 悲观锁 | 默认一定会冲突,操作前上锁 | synchronized、ReentrantLock |
| 乐观锁 | 默认不会冲突,提交时校验冲突 | CAS、AtomicInteger | |
| synchronized底层实现 | 重量级锁 | 依赖OS内核,线程挂起 | 高竞争下的synchronized |
| 轻量级锁 | 用户态,无内核调用,低竞争 | 交替使用锁的synchronized | |
| 抢锁失败行为 | 挂起等待锁 | 抢不到锁,线程休眠,让出CPU | synchronized重量级锁 |
| 自旋锁 | 抢不到锁,循环重试,占用CPU | CAS自旋锁 |
⚠️高频易错点(考试常坑)
- 悲观锁 ≠ 重量级锁。
synchronized既是悲观锁,又可以从轻量级锁膨胀到重量级锁。 - 乐观锁没有阻塞,依靠CAS自旋重试;乐观锁不等于自旋锁。
- 自旋锁只是等待策略,可以是乐观锁,也可以是悲观锁。
- 轻量级锁不是乐观锁!轻量级锁仍然属于悲观锁(它假设会有竞争,只是竞争不激烈)。
一句话速记
- 悲观乐观:预判会不会冲突
- 轻重量级:synchronized底层,要不要找操作系统内核
- 自旋/挂起:抢不到锁,是循环重试,还是睡觉放弃CPU