资讯详情 Redisson 看门狗那 30 秒,源码里写在 Config.java 第 82 行
📅 2026/10/11 18:57:43
➡️ 程序员曜灵 · 后端面试追问链 - 欢迎认识我作者程序员曜灵,绿泡泡「我要拿offer」和小红书同名。主业在一家大型央企做后端开发,Java 方向,参与过公司内部招聘面试。这里在拆高频面试题的追问链,一题三层,每层给及格线答案和大多数人挂在哪。工作日每天一篇,评论区点最高频的问题决定下一篇写什么。Redisson 看门狗这题我听过十几遍,答案几乎都一样。默认 30 秒,每隔 10 秒续一次,客户端挂了锁就永远不释放。前两句方向没错,第三句是反的。而前两句我每次追问出处,没有一个人给得出来。今天就把这三句话在源码里对一遍。下面所有行号取自 Redisson master 分支,今天能打开核对。30 秒不是秒,是毫秒org/redisson/config/Config.java第 82 行。privatelonglockWatchdogTimeout30*1000;紧接着第 84 行,这一行绝大多数讲看门狗的文章里没有。privateintlockWatchdogBatchSize100;第 82 行的单位是毫秒。30 * 1000是超时时长,不是30 秒这个数本身。差别在面试里不算小事,因为 setter 的注释就写明了单位。同一个文件第 660 行,setLockWatchdogTimeout的参数说明是timeout in milliseconds。背成30 秒的人,被追问那我要设成 1 分钟该传什么,有一半会传个60。传 60 等于把锁的超时设成 60 毫秒。续期周期藏在 RenewalTask 里org/redisson/renewal/RenewalTask.java第 67、68 行。longinternalLockLeaseTimeexecutor.getServiceManager().getCfg().getLockWatchdogTimeout();executor.getServiceManager().newTimeout(this,internalLockLeaseTime/3,TimeUnit.MILLISECONDS);周期是internalLockLeaseTime / 3,也就是超时时长的三分之一。默认配置下确实是 10 秒,但它是算出来的,不是写死的常量。这个区别决定了追问能不能接住。lockWatchdogTimeout一改,续期周期跟着变。有人背30 秒配 10 秒,你把超时改成 90 秒,续期就跟着变成 30 秒,那个10根本不成立。RedissonLock.java第 61 行是这条链的起点。this.internalLockLeaseTimegetServiceManager().getCfg().getLockWatchdogTimeout();你显式传了 leaseTime,看门狗就不管了前面三条都是数值记错,这一条是行为记错,也是这题上候选人和写过线上代码的人差别最大的一处。RedissonLock.java第 162 到 177 行的逻辑是这样的。tryLock拿到锁之后先判断leaseTime 0。你传了过期时间,就把internalLockLeaseTime覆盖成你给的值,然后直接返回,不调scheduleExpirationRenewal。只有你没传的时候,才会走到第 177 行去注册续期任务。if(leaseTime0){internalLockLeaseTimeunit.toMillis(leaseTime);}else{scheduleExpirationRenewal(threadId);}所以lock(10, TimeUnit.SECONDS)这种写法,看门狗从头到尾没参与。锁到 10 秒就没了,业务没跑完就是事故。第 327 到 330 行的cancelExpirationRenewal里还有一句细节,取消续期之后internalLockLeaseTime会被重置回配置值,这是为了同一个 RedissonLock 实例复用时不带脏状态。客户端宕机,锁不会永远不释放续期是客户端进程里的 Netty 定时任务,不是 Redis 服务端的行为。进程没了,定时器跟着没了,没人续期,锁最多活到lockWatchdogTimeout就自动过期。Config.java第 652 行的注释就是这么写的,锁在lockWatchdogTimeout之后过期,前提是看门狗没有把它续到下一个时间区间。那句话反过来说才是对的。看门狗解决的是业务没跑完锁先没了,它不解决进程崩了锁还占着。后者靠的还是超时自动释放。3.44.0 之后,续期改成批量了这一条是版本时间线,讲看门狗的文章基本没跟上。Redisson 3.44.0(发布于 2025-01-27)的 release note 里有一条Feature - lockWatchdogBatchSize setting added。对应到代码,RenewalTask里现在是MapInteger, SetString slot2names加MapString, LockEntry name2entry两个结构,配合上面那个chunkSize,一轮定时器扫一批锁,而不是每把锁各占一个定时任务。一个进程里持几千把锁的场景,这个改动是有实际意义的。老写法下几千个定时器任务在时间轮里排着,续期的抖动会明显变大。再往后,4.2.0(2026-02-05)的 release note 里还有一条docs: update deprecation note for RedLock object。RedLock 那个对象官方一直在补废弃说明。今天写这篇的时候最新 release 是 redisson-4.8.0,2026-10-02。一张表把默认值钉住参数或字段值单位起始版本出处lockWatchdogTimeout30 * 1000毫秒长期存在Config.java第 82 行lockWatchdogBatchSize100把3.44.0(2025-01-27)Config.java第 84 行续期周期internalLockLeaseTime / 3毫秒长期存在RenewalTask.java第 68 行显式leaseTime覆盖internalLockLeaseTime,不注册续期毫秒长期存在RedissonLock.java第 162-177 行取消续期后internalLockLeaseTime重置回配置值毫秒长期存在RedissonLock.java第 327-330 行面试里我会怎么分层第一层,能说默认 30 秒,每 10 秒续一次。这算看过文章,我不扣人也不加分,因为这句话在十几个来源里都能抄到。第二层,知道那个 10 是/ 3算出来的,知道改了lockWatchdogTimeout续期周期会跟着变。这一层说明他理解机制而不是记结论。第三层,我问他lock(10, TimeUnit.SECONDS)和lock()的区别。答一个走看门狗一个不走就到位了。能补一句不走的这把锁到期就没了,业务超时是真实故障,我会开始考虑给过。第四层,宕机那句他自己纠正过来,顺带说续期是客户端定时器、Redis 服务端不管这件事。到这一层我会问他项目里一把锁最长持有多久、怎么测出来的。真上过线的人这里会有具体数字,而且数字不好看。出处Config.java第 82、84、652、660 行,RedissonLock.java第 52、61、162-177、327-330 行,RenewalTask.java第 48-52、67-68 行,均取自 GitHub 仓库redisson/redissonmaster 分支,通过 GitHub contents API 拉取原文,2026-10-10 核对。3.44.0 与 4.2.0 的 release note 条目、redisson-4.8.0 的发布日期,取自api.github.com/repos/redisson/redisson/releases。上面那句传 60 等于把超时设成 60 毫秒是我按 setter 注释推的,不是官方原文,生产上真要改这个参数,先在你自己的环境里打印一次getLockWatchdogTimeout()确认。最后如果觉得这篇有用,可以点赞收藏关注 支持一下,程序员曜灵的主页还有很多按追问链拆的面试题,欢迎前去点评。哪里讲得不准,评论区指出,我改在这篇的更新里。欢迎学习交流、面试问题求助、共同进步。绿泡泡【我要拿offer】,回复 Redis 拿那份按模块整理的高频面试题 PDF。想看每日面经和 offer 案例的,小红书同名号程序员曜灵。