Synchronized底层机制:偏向锁、轻量级锁与重量级锁及其锁升级过程

前言:

在Java并发编程中,synchronized关键字是用于实现线程同步的重要工具。在JVM中,synchronized的底层实现涉及到了偏向锁、轻量级锁和重量级锁这三种锁状态,以及锁升级过程。在之前的文章中介绍到过,这篇文章详细对锁升级进行说明。

偏向锁

偏向锁是Java 6中引入的一种优化手段,它的核心思想是:如果一个线程获得了锁,并且没有释放,那么下次当这个线程再次尝试获得这个锁的时候,不需要做任何同步操作,不需要进行CAS操作或者阻塞,可以直接获得这个锁。偏向锁主要是为了避免无竞争情况下的同步原语,进一步提高程序的运行性能。

如何获取偏向锁

当一个线程首次访问同步块并获取锁时,会在对象头和栈帧中的锁记录里存储偏向的线程ID。

在后续操作中,如果这个线程再次尝试获得这个锁,JVM只需检查对象头的Mark Word里是否存储着指向当前线程的偏向锁。如果是,就表示线程已经获得了锁,可以继续执行同步代码块。

如何撤销偏向锁

当一个线程释放偏向锁时,JVM并不会立即清除对象头中的偏向线程ID,而是将其设置为一个特殊值,表示该锁已经被释放。这样,当其他线程尝试获取这个锁时,JVM会检测到这个特殊值,从而知道该锁已经被释放,可以重新进行偏向锁的获取操作。

轻量级锁

轻量级锁是为了减少获得锁和释放锁所带来的性能消耗而引入的。在锁竞争不激烈的情况下,轻量级锁可以提高程序的性能。它的实现主要依赖于自旋和CAS操作。

如何轻量级锁

当线程尝试获取一个被其他线程持有的轻量级锁时,它会进入自旋状态,尝试通过CAS操作获取锁。如果自旋等待超过预定的次数仍然没有成功获得锁,那么该线程将会被挂起,转换为重量级锁。在Java 6之后,对于非偏向锁的同步块,在第一次被访问时也会尝试使用轻量级锁。

如何轻量级锁

轻量级锁的释放过程相对简单。当持有锁的线程释放锁时,只需将对象头中的Mark Word设置为无锁状态即可。这样,其他线程就可以尝试获取这个轻量级锁了。

重量级锁

重量级锁是传统的同步锁实现方式,它在JVM中是通过对象监视器Monitor来实现的。当一个线程尝试获取一个被其他线程持有的重量级锁时,它会被阻塞并放入锁的等待队列中。

当持有锁的线程释放锁时,等待队列中的一个线程会被唤醒并获得锁。这种实现方式虽然保证了线程安全,但是在竞争激烈的情况下会导致大量的线程切换和上下文切换,从而带来较大的性能开销。

锁升级过程

接下来详细介绍一下锁升级的过程,这块也是面试中的重点!

在JVM中,synchronized的底层实现涉及到了偏向锁、轻量级锁和重量级锁这三种锁状态的转换过程,即锁升级过程。

当一个线程首次访问同步块并获得锁时,该锁的状态为偏向锁。

在后续的操作中,如果该线程再次尝试获得这个锁,JVM会检查该锁的状态并进行相应的处理。如果该锁的状态为偏向锁且偏向的线程ID与当前线程的ID相同,则表示该线程已经获得了锁,可以继续执行同步代码块;如果该锁的状态为偏向锁但偏向的线程ID与当前线程的ID不同,则表示该锁已经被其他线程持有,需要进行竞争。

此时,JVM会将该锁的状态升级为轻量级锁或重量级锁,具体取决于竞争的激烈程度。如果竞争不激烈,JVM会尝试使用CAS操作获取轻量级锁;如果竞争激烈或自旋等待超过预定的次数仍然没有成功获得轻量级锁,则将该锁的状态升级为重量级锁并阻塞当前线程放入等待队列中等待唤醒。

当持有锁的线程释放锁时也会根据当前锁的状态进行相应的处理。如果当前锁的状态为重量级则唤醒等待队列中的一个线程并获得锁;如果当前锁的状态为轻量级或偏向则只需将对象头中的Mark Word设置为无锁状态即可。

相关推荐
弈栈录13 小时前
流式对话接口设计:SSE、WebSocket 与断线重连
后端
Java内核笔记14 小时前
Spring AI 生产级 Chat 接口:6 个开关、13 个坑,其中 2 个开关根本没生效
java·人工智能·后端
是江迪呀14 小时前
向全世界售卖你的产品:做了一款教程引导插件
前端·javascript·后端
WeiXin_DZbishe14 小时前
基于springboot装修风格选择系统的设计与开发-计算机毕设【课程设计】77964
java·vue.js·spring boot·后端·python·php·课程设计
leikooo14 小时前
ARTS 1018: 字符计数判断异位词、局部做对仍会增加维护负担与用 AI 也要理解自己在做什么
后端
一步一脚印15614 小时前
对于JVM的简单理解 一
后端
1360967572314 小时前
证书签不下来,是因为 well-known 被反代了
后端
Yeswater14 小时前
从 NIO 到 Netty:五个坑,和一张把它填平的基础设施网
java·后端·netty
福大大架构师每日一题14 小时前
2026-10-18:转换字符串的最小成本Ⅲ。用go语言,给定两个字符串 source 和 target,以及若干条替换规则。每条规则包含一个模式串、一个替换串
后端
韩振方15 小时前
Kubernetes Secret 让数据库密码离开镜像和 Pod 配置
后端