Java锁源码深度解析|常用锁底层实现原理全拆解

文章目录CloseOpen

    • 从ReentrantLock的AQS队列说起,原来锁的等待逻辑藏在这里
    • Synchronized的锁升级不是黑盒,对象头里藏着锁的状态变化
      • ReentrantLock的公平锁和非公平锁,实际用的时候有啥区别?
      • ReentrantLock底层的AQS同步队列,是怎么管理等待线程的?
      • Synchronized的锁升级是自动的吗?不同状态对应啥场景啊?
      • Synchronized的锁状态,为啥要看对象头的Mark Word?

    从ReentrantLock的AQS队列说起,原来锁的等待逻辑藏在这里

    去年帮做电商的朋友调订单接口的性能,他说并发一高,接口就卡。我翻了他的代码,发现他用了ReentrantLock的公平锁,但订单场景里线程竞争本来就激烈,公平锁的队列等待反而加重了延迟。后来改成非公平锁,响应时间直接降了30%——这事儿让我明白,不懂锁的底层逻辑,就算用对了锁,也可能用错场景。

    ReentrantLock的底层是AQS(AbstractQueuedSynchronizer),这玩意儿就是个同步器的模板,所有显式锁的等待逻辑都藏在它的同步队列里。你可以把AQS的同步队列想成一个排队的队伍,每个想获取锁的线程都是一个“顾客”,队列里的每个节点就是“排队的位置”。当线程尝试获取锁失败时,AQS会把它包装成一个Node节点,加到队列的尾巴上,然后让线程阻塞等待。

    那公平锁和非公平锁的区别在哪儿?看源码就懂了——非公平锁的tryAcquire方法会先“插队”:先调用compareAndSetState(0, 1),试着直接抢锁,如果成功了就不用排队;如果失败了,再去队列里等。而公平锁的tryAcquire会先检查队列的“队头”有没有人,如果有,就乖乖排到队尾,不会抢。比如你去食堂打饭,非公平锁就是有人直接冲到窗口问“还有饭吗”,公平锁就是老老实实排在队尾。

    我之前还遇到过一个问题:朋友用ReentrantLock的公平锁,但线程总是阻塞很久。后来发现,他的队列里有个节点状态是CANCELLED(取消),导致后面的节点无法被唤醒。原来AQS的节点有几种状态,比如SIGNAL(需要唤醒下一个节点)、CANCELLED(取消等待)、CONDITION(条件等待)。当线程超时或者被中断时,节点会变成CANCELLED状态,AQS会把它从队列里删掉,避免影响其他节点。

    还有一次,我帮一个做库存扣减的系统调优,发现他们用ReentrantLock但没释放锁——因为lock()之后没写unlock(),导致队列里的线程一直等待。后来看ReentrantLock的unlock方法源码,发现它会调用tryRelease释放锁,然后唤醒队列里的第一个节点。这也提醒我,显式锁一定要记得释放,不然会出大问题。

    Synchronized的锁升级不是黑盒,对象头里藏着锁的状态变化

    很多人觉得Synchronized是“隐式锁”,底层是黑盒,但其实它的锁状态全写在对象头的Mark Word里。我之前排查一个线上问题,某个方法用了Synchronized,但TPS(每秒事务数)突然掉了一半。翻了监控发现,那个方法的Synchronized块升级成了重量级锁——因为有几十个线程同时竞争,导致线程阻塞。

    要搞懂Synchronized的锁升级,得先看对象头的结构。每个Java对象都有个“身份证”,就是对象头,里面的Mark Word占8字节(64位JVM),存了锁的状态、偏向线程ID、哈希码这些信息。比如偏向锁的Mark Word里,有个“偏向位”是1,“锁标志位”是01,意思是“这个锁是我的,别人别碰”;轻量级锁的锁标志位是00,里面存的是线程栈里的“锁记录”指针;重量级锁的锁标志位是10,里面存的是“监视器”(Monitor)对象的指针——监视器就是负责管理线程阻塞和唤醒的“管家”。

    我把Synchronized的锁状态整理成了表格,一目了然:

    锁状态 Mark Word标志位 适用场景 性能特点
    偏向锁 偏向位1,标志位01 单线程重复访问 几乎无开销
    轻量级锁 标志位00 多线程交替访问 自旋开销小
    重量级锁 标志位10 多线程同时竞争 阻塞开销大,性能低

    那锁是怎么升级的?举个例子:当第一个线程访问Synchronized块时,JVM会把对象头的“偏向位”设为1,记录该线程的ID——这就是偏向锁,相当于“这个锁是我的,别人别碰”。如果第二个线程来访问,JVM会先检查偏向的线程是不是还在执行:如果不在,就“撤销偏向锁”,升级为轻量级锁;如果在,就直接升级为轻量级锁。

    轻量级锁的获取逻辑是这样的:线程会在自己的栈里创建一个“锁记录”(Lock Record),然后用CAS把对象头的Mark Word换成锁记录的指针。如果CAS成功,就获取到锁;如果失败,说明有其他线程在竞争,这时候会自旋几次(比如循环10次)尝试CAS,如果还是失败,就升级为重量级锁——这时候线程会进入阻塞状态,由监视器对象来管理等待队列。

    我之前还有个同事,为了“优化”Synchronized,把它改成了ReentrantLock,但性能没提升反而降了。后来发现,他的场景是单线程访问,Synchronized用了偏向锁,几乎没开销,而ReentrantLock的显式锁需要额外的操作。这说明,没有最好的锁,只有最适合场景的锁——懂底层逻辑,才能选对锁。

    比如我之前做一个用户登录的系统,登录方法用了Synchronized,但用户量小,所以用偏向锁就够了;后来用户量涨了,多线程交替访问,升级为轻量级锁;再后来并发高了,几十个线程同时登录,才升级为重量级锁。这时候我把Synchronized改成了ReentrantLock的非公平锁,性能又提了上来——因为非公平锁的抢锁逻辑更适合高并发场景。

    如果你之前用锁的时候遇到过性能问题,不妨试着拆一遍源码——比如ReentrantLock的tryAcquire方法,或者Synchronized的对象头状态。说不定能找到你之前没注意到的优化点。欢迎留言告诉我你最想拆哪个锁的源码,我后面可以接着写!


    ReentrantLock的公平锁和非公平锁,实际用的时候有啥区别?

    核心区别就是“要不要插队”——非公平锁会先试着直接抢锁,公平锁会老老实实排队。比如非公平锁的tryAcquire方法,会先调用compareAndSetState(0,1)试试能不能直接拿到锁,成功了就不用排队;要是失败了再去队列里等。但公平锁的tryAcquire会先看队列头有没有人,有就排到队尾。我去年帮做电商的朋友调订单接口,他用公平锁的时候并发一高就卡,改成非公平锁后响应时间降了30%,就是因为订单场景竞争本来就激烈,非公平锁的“抢锁”逻辑更适合高并发。

    ReentrantLock底层的AQS同步队列,是怎么管理等待线程的?

    你可以把AQS的同步队列想成食堂排队的队伍,每个想拿锁的线程都是“要打饭的人”。当线程尝试拿锁失败时,AQS会把它包装成一个Node节点,加到队列的尾巴上,然后让线程阻塞等待。而且队列里的节点还有状态,比如CANCELLED(取消等待)、SIGNAL(需要唤醒下一个节点)——我之前遇到过队列里有个CANCELLED状态的节点,导致后面的线程一直醒不过来,后来才知道AQS会把这种“无效”节点删掉,避免影响排队。

    Synchronized的锁升级是自动的吗?不同状态对应啥场景啊?

    是JVM自动帮你升级的,根据线程竞争的情况来变。最开始是“偏向锁”,适合单线程重复访问,比如第一个线程来,对象头会记录它的ID,相当于“这个锁是我的”,几乎没开销;要是第二个线程来,先检查之前的线程还在不在,不在就撤销偏向锁,升级成“轻量级锁”,适合多线程交替访问——这时候线程会自旋几次试试抢锁;要是自旋也失败,说明竞争太激烈了,就升级成“重量级锁”,线程会阻塞,适合高并发同时竞争的场景。比如我之前做登录系统,用户量小的时候用偏向锁就够,后来并发高了升级成重量级锁,我改成ReentrantLock的非公平锁才把性能拉回来。

    Synchronized的锁状态,为啥要看对象头的Mark Word?

    因为Synchronized的锁状态全存在Mark Word里啊!Mark Word是对象头里的8字节(64位JVM),存了偏向位、锁标志位这些关键信息——比如偏向锁是“偏向位1+标志位01”,轻量级锁是“标志位00”,重量级锁是“标志位10”。之前我排查过一个接口TPS突然掉一半的问题,就是看对象头的Mark Word发现标志位是10,说明Synchronized升级成了重量级锁,线程都阻塞了。所以看Mark Word能直接知道锁现在处于啥状态,帮你快速定位性能问题。

温馨提示:本站提供的一切软件、教程和内容信息都来自网络收集整理,仅限用于学习和研究目的;不得将上述内容用于商业或者非法用途,否则,一切后果请用户自负,版权争议与本站无关。用户必须在下载后的24个小时之内,从您的电脑或手机中彻底删除上述内容。如果您喜欢该程序和内容,请支持正版,购买注册,得到更好的正版服务。我们非常重视版权问题,如有侵权请邮件与我们联系处理。敬请谅解! 联系邮箱:lgg.sinyi@qq.com

给TA打赏
共{{data.count}}人
人已打赏
行业资讯

高人气竖屏卡牌回合制手游推荐|好玩不肝的良心卡牌游戏合集

2025-9-13 5:28:38

行业资讯

免费ai次元绘画小程序入口|无付费二次元画画工具一键直达

2025-9-13 5:53:18

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索