news 2026/11/5 19:39:57

Java锁机制底层原理与synchronized、AQS、CAS详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Java锁机制底层原理与synchronized、AQS、CAS详解

先说一个我在面试和带人过程中反复遇到的场景:Java并发这块,面试官最爱问的除了线程池就是锁机制。几乎每个人都能背出synchronized和ReentrantLock的区别,可你再往下追问一句"偏向锁升级到轻量级锁,底层到底动了什么",能讲清楚的就不多了。锁机制之所以成为"八股文重灾区",是因为它的知识链条特别长——从CPU指令、JVM内存模型到JDK工具类,每一层都有说法,而大部分人的学习只停在了最表层的结论上。

这篇文章不打算做那种单纯的八股背诵,我想把Java锁机制从底层到使用整个串一遍:synchronized在对象头里怎么玩状态位,ReentrantLock背后的AQS到底怎么排队,CAS是怎么做到"不加锁的锁",volatile在什么场景下能替代锁、什么场景下不能。你既可以拿着它准备面试,也能在真正排查并发问题的时候翻回来看看。我尽量用大白话讲原理,该给代码给代码,该给参数给参数,都是实际能落地的东西。

1. 为什么锁机制是并发八股文的重灾区

1.1 锁要解决的三类问题

先回到最底层。多线程同时访问共享资源,归根结底会出三类问题:互斥、可见性、有序性。这三个词是理解所有锁的前提,也是面试连环问的起点。

互斥不用多解释,同一时刻只能有一个线程进入临界区。可见性说的是:线程A把数据改了,线程B不一定能立刻看到,因为CPU缓存和主内存之间存在中间层。有序性就更隐蔽了,编译器、JIT、CPU都可能为了性能打乱指令的执行顺序,这在单线程下没影响,多线程下就可能出事。

锁这件事,表面上是保护一段代码,本质上是在这三个维度上建立屏障。synchronized能做到,volatile只能管可见性和有序性,管不了互斥。把这个底层逻辑理清了,后面所有概念都不会散。

1.2 一把锁,可以从四个维度去看

业界习惯把"锁"这个词按各种维度切分,新手最容易懵的就是这里。我见过有人把"乐观锁"和"轻量级锁"搞混,其实它们的分类维度完全不一样。

维度分类典型代表一句话理解
竞争态度悲观锁 / 乐观锁synchronized / CAS悲观锁认为一定冲突,乐观锁假设大多不冲突
获取顺序公平锁 / 非公平锁ReentrantLock 两种构造先来后到,还是允许插队
重入能力可重入 / 不可重入ReentrantLock / 自定义锁同一线程能否反复持有
占用模式独占 / 共享ReentrantLock / 读写锁一把锁是只能一人用,还是可以多人读
JVM锁状态偏向锁 / 轻量级锁 / 重量级锁synchronized 的三态同一把synchronized锁的升级过程
加锁方式自旋 / 阻塞CAS循环 / 重量级锁失败后是转圈重试还是挂起

这个表格建议你存下来。面试的时候,只要能把"维度"说清楚,再举一个反面例子,就已经超过了大多数人。

1.3 八股文的正确学法

我自己面试别人的时候,最怕听到的答案是那种背得很顺、却经不起追问的结论。"偏向锁性能高?为什么高?""synchronized在JDK6之后优化了?优化了什么?"答案一旦是"因为JVM优化了",在我这里基本就挂了。

正确的学法是把每个结论往底层追问一层:偏向锁效率高,是因为加锁时只需要比对线程ID,连CAS都不需要;synchronized性能提升,是因为引入了锁升级机制,减少了用户态和内核态的切换次数。概念落到原理上,八股文就变成了真技术。接下来我就按这个思路,把锁机制一层层拆开。

2. synchronized的底层宇宙:对象头、Mark Word与锁升级路线

2.1 每个Java对象天生带着锁的元数据

synchronized锁的是对象,但锁信息存在哪里?答案在对象头里。每个Java对象的内存布局里,最前面有一段叫Mark Word的区域,用来记录对象的运行时数据:hashCode、GC分代年龄、锁状态等。

关键点是:Mark Word是一块可复用的内存。锁状态不同,它里面记录的东西就完全不同。无锁状态下它存hashCode和分代年龄;变成偏向锁后,腾出大部分空间存偏向的线程ID;变成轻量级锁后,存指向线程栈中锁记录的指针;变成重量级锁后,存指向ObjectMonitor的指针。

所以synchronized的加锁过程,本质上就是根据竞争情况不断改写对象头里那几位标志位的过程。

2.2 锁状态编码:一张表看懂对象头的秘密

在HotSpot虚拟机里,Mark Word的最低2位叫lock标志位,旁边还有一个1位的biased_lock标志位,组合起来就能表示四种锁状态:

锁状态biased_locklock标志位Mark Word里存的什么
无锁001hashCode、GC分代年龄
偏向锁101偏向线程ID、epoch、分代年龄
轻量级锁000指向栈中Lock Record的指针
重量级锁010指向ObjectMonitor的指针
GC标记-11转发指针等

这里有个容易踩的坑:偏向锁和无锁的lock标志位都是01,区别在于biased_lock那一位。所以判断一个对象是否可偏向,要看完整的低三位对不对。

2.3 偏向锁:单线程反复加锁的"绿色通道"

偏向锁的思想非常朴素:如果一个线程反复获得同一把锁,那就让这个线程"偏向"它,之后加锁只需要检查Mark Word里记录的线程ID是不是自己,是就直接进临界区,连CAS都不用,更不需要陷入内核态。

偏向锁的获取流程大概是这样的:

  1. 检查Mark Word是否为可偏向状态。
  2. 如果可偏向,尝试通过CAS把当前线程ID写入Mark Word。
  3. 如果成功,当前线程获得锁,后续重入只需要比对线程ID。
  4. 如果CAS失败,说明存在竞争,需要撤销偏向。

注意,偏向锁的撤销不是当前线程自己做的。JVM会等到全局安全点(SafePoint),暂停持有偏向锁的线程,再判断这个线程到底有没有退出临界区。如果已经退出了,就把对象头改回无锁或轻量级锁状态;如果还在临界区里跑,就直接升级成重量级锁,让线程真正阻塞。

经验提醒:偏向锁的撤销成本其实不低,因为它要等安全点、暂停线程。低竞争时偏向锁省下的CAS开销,未必能抵消偶尔一次撤销的开销。这也是后来JVM团队对它动刀的原因。

2.4 批量重偏向与批量撤销:一类对象的"群体事件"

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/29 12:32:26

Cadence ADE环境下VCO相位噪声仿真:PSS与Pnoise参数设置详解

做模拟射频IC的朋友,十有八九都被VCO相位噪声仿真折磨过。刚接触Cadence ADE那会儿,我在PSS和Pnoise的设置界面里来回折腾,要么仿真到一半直接不收敛,要么跑出来的相位噪声曲线在低频端完全不合物理直觉。等把整个流程吃透之后回头…

作者头像 李华
网站建设 2026/10/25 7:47:04

AI编程智能体:普通程序员生产力翻倍的实战指南

最近“AI 编程智能体”这个词热得快,从大厂发布会到技术社区的帖子,到处都在提。作为写了十几年代码的老程序员,我一开始也抱着观望态度,直到自己亲手把几个真实项目交给智能体去跑,才意识到这轮变化和以往那些“AI帮你…

作者头像 李华
网站建设 2026/11/5 11:31:28

算能1684x部署qwen3-vl多模态RAG:私有知识库问答实战

最近一周,我把一台装着算能1684x的机器和一台上线了腾讯开源RAG知识库weknora的服务器接在了一起,中间塞进一个qwen3-vl多模态模型,组了一套既能检索文档、又能“看图说话”的私有知识问答系统。整个折腾下来,最深的感受是&#x…

作者头像 李华
网站建设 2026/11/5 10:26:32

DeepSeek Harness桌面端实测:工作流编排、插件与技能部署指南

DeepSeek Harness 出了桌面端?我看到消息的当天就把安装包拖下来试了一圈,怎么说呢,比起之前一直在终端里敲命令的方式,这一次它确实把门坎往下拉了一大截。先说结论:DeepSeek Harness 桌面端不是简单套了个网页壳&…

作者头像 李华
网站建设 2026/10/25 13:45:50

Agent工程化解剖:全插件化架构与可回放会话日志的落地实践

引言 做 Agent 开发做得越久,越会撞上一个尴尬局面:demo 阶段效果惊艳,一路跑通各种小任务,可真要把这套东西放上线、交给团队维护、让它在生产环境里稳定迭代,所有"精致"都会变成"玄学"。改了一行…

作者头像 李华
网站建设 2026/10/30 10:10:58

SLG深度优化实战:从包体瘦身到社交生态的长线运营复盘

做SLG项目调优这些年,我电脑里存得最多的不是新功能策划案,而是各种版本复盘。《乱世王者》这个项目常被同行拿来问:一款三国题材的畅销SLG,核心玩法不外乎城建、行军、出征、联盟对抗,凭什么能长期站在畅销榜头部&…

作者头像 李华