轻量级锁与重量级锁的区别

115 阅读3分钟

前言

在 Java 并发编程中,锁机制是保障线程安全的重要手段。Monitor 锁作为其中的核心概念,又可细分为轻量级锁和重量级锁。它们就像两种不同风格的 “门锁管理方式”,在不同的竞争场景下各展所长。下面,让我们一起深入探究这两种锁的奥秘。

前置知识:Monitor 是什么?

Monitor 即监视器,它宛如一个 “智能门岗”,承担着管理线程进入同步代码(临界区)的重任。在 Java 中,每个对象都天然自带一个 Monitor,恰似每个房间都配备了一个专属门岗,负责把控线程的进出权限。

轻量级锁:“和平时期” 的高效管理

轻量级锁适用于线程交替使用锁的场景,例如线程 A 使用完后线程 B 接着用,线程 B 用完后线程 A 再用,线程间竞争并不激烈。

工作方式

当线程想要进入临界区时,会先在自己的 “小本本”(线程栈)上记录 “我要锁这个门”,随后通过 CAS(一种无锁操作) 告知门岗 “这次由我使用,请记录一下”。若此时没有其他线程竞争,门岗会直接记录,线程得以顺利进入,整个过程都在 “用户态” 进行,无需麻烦操作系统内核,速度极快。即便出现轻微冲突,线程也不会立刻进入排队等待状态,而是选择 “自旋”,即在原地等待片刻,看看持有锁的线程是否很快就会释放,以此避免频繁的线程阻塞。

优缺点对比

场景轻量级锁重量级锁
竞争程度低(线程交替使用)高(多线程同时抢)
实现方式基于 CAS + 自旋(用户态操作)基于操作系统内核(内核态操作)
线程状态抢不到锁时自旋(活跃状态)抢不到锁时阻塞(休眠状态)
效率高(无内核切换开销)低(有内核切换开销)
对应门岗风格自助登记(简单高效)专人管理(严格但麻烦)

重量级锁:“混乱时期” 的严格管理

重量级锁适用于多线程同时争抢锁的场景,例如 10 个线程同时试图进入临界区,竞争异常激烈。

工作方式

当线程尝试获取锁时,若发现已有其他线程持有该锁,就会将控制权交给 “操作系统内核”(进入内核态)。内核会把未能抢到锁的线程放入 “等待队列”,就像在排队叫号一样,此时线程进入阻塞状态,不再消耗 CPU 资源。当持有锁的线程使用完毕后,会通知内核释放锁,内核再从等待队列中唤醒一个线程来尝试获取锁。

锁的升级过程

JVM 具备智能调节能力,会依据竞争情况自动对锁的类型进行升级(只能升级,不能降级),具体过程如下:

  • 初始状态为无锁状态,此时没有线程使用该锁。
  • 若仅有一个线程使用锁,会升级为偏向锁,直接记住该线程,后续该线程再使用时无需每次都进行登记操作。
  • 当出现轻微竞争,即线程交替使用锁时,升级为轻量级锁,采用 CAS + 自旋的方式。
  • 一旦竞争变得激烈,多线程同时争抢锁,就会升级为重量级锁,交由内核进行管理。

总结

总结

  • 轻量级锁是 “灵活高效的自助管理”,适合人少的时候;
  • 重量级锁是 “严格但笨重的专人管理”,适合人多的时候。

JVM 自动根据 “人多人少” 切换方式,目的是在 “安全” 和 “效率” 之间找平衡。