前言:
在 Java 并发编程中,锁机制是保障线程安全的重要手段。Monitor 锁作为其中的核心概念,又可细分为轻量级锁和重量级锁。它们就像两种不同风格的 “门锁管理方式”,在不同的竞争场景下各展所长。下面,让我们一起深入探究这两种锁的奥秘。
前置知识:Monitor 是什么?
Monitor 即监视器,它宛如一个 “智能门岗”,承担着管理线程进入同步代码(临界区)的重任。在 Java 中,每个对象都天然自带一个 Monitor,恰似每个房间都配备了一个专属门岗,负责把控线程的进出权限。
轻量级锁:“和平时期” 的高效管理
轻量级锁适用于线程交替使用锁的场景,例如线程 A 使用完后线程 B 接着用,线程 B 用完后线程 A 再用,线程间竞争并不激烈。
工作方式
当线程想要进入临界区时,会先在自己的 “小本本”(线程栈)上记录 “我要锁这个门”,随后通过 CAS(一种无锁操作) 告知门岗 “这次由我使用,请记录一下”。若此时没有其他线程竞争,门岗会直接记录,线程得以顺利进入,整个过程都在 “用户态” 进行,无需麻烦操作系统内核,速度极快。即便出现轻微冲突,线程也不会立刻进入排队等待状态,而是选择 “自旋”,即在原地等待片刻,看看持有锁的线程是否很快就会释放,以此避免频繁的线程阻塞。
优缺点对比
| 场景 | 轻量级锁 | 重量级锁 |
|---|---|---|
| 竞争程度 | 低(线程交替使用) | 高(多线程同时抢) |
| 实现方式 | 基于 CAS + 自旋(用户态操作) | 基于操作系统内核(内核态操作) |
| 线程状态 | 抢不到锁时自旋(活跃状态) | 抢不到锁时阻塞(休眠状态) |
| 效率 | 高(无内核切换开销) | 低(有内核切换开销) |
| 对应门岗风格 | 自助登记(简单高效) | 专人管理(严格但麻烦) |
重量级锁:“混乱时期” 的严格管理
重量级锁适用于多线程同时争抢锁的场景,例如 10 个线程同时试图进入临界区,竞争异常激烈。
工作方式
当线程尝试获取锁时,若发现已有其他线程持有该锁,就会将控制权交给 “操作系统内核”(进入内核态)。内核会把未能抢到锁的线程放入 “等待队列”,就像在排队叫号一样,此时线程进入阻塞状态,不再消耗 CPU 资源。当持有锁的线程使用完毕后,会通知内核释放锁,内核再从等待队列中唤醒一个线程来尝试获取锁。
锁的升级过程
JVM 具备智能调节能力,会依据竞争情况自动对锁的类型进行升级(只能升级,不能降级),具体过程如下:
- 初始状态为无锁状态,此时没有线程使用该锁。
- 若仅有一个线程使用锁,会升级为偏向锁,直接记住该线程,后续该线程再使用时无需每次都进行登记操作。
- 当出现轻微竞争,即线程交替使用锁时,升级为轻量级锁,采用 CAS + 自旋的方式。
- 一旦竞争变得激烈,多线程同时争抢锁,就会升级为重量级锁,交由内核进行管理。
总结
总结
- 轻量级锁是 “灵活高效的自助管理”,适合人少的时候;
- 重量级锁是 “严格但笨重的专人管理”,适合人多的时候。
JVM 自动根据 “人多人少” 切换方式,目的是在 “安全” 和 “效率” 之间找平衡。