手写轻量级Redis分布式锁:SET NX PX + Lua脚本实战与避坑
先聊个实际感受分布式锁这个话题博客里写烂了但全网搜下来能直接抄回家就用的轻量级Redis分布式锁实现反而是少数。我最早做分布式锁和大多数人一样直接引入Redisson完事。后来接手一个项目里面有一段手写的Redis锁代码代码不多却把加锁、解锁、异常处理这些细节抠得很清楚。当时项目体量不大Redis单节点也够用Redisson那一大坨依赖和黑盒行为反而成了负担。我把那段代码整理成了自己的一个轻量级锁工具类也把几个经典事故——锁误删、锁过期业务没跑完、主从切换丢锁、Lettuce连接超时——逐个踩了一遍。这篇文章就讲这条“不加框架、只用Redis原生命令和少量Java代码”就能做出可用分布式锁的路子。会拆解SET NX PX这几个命令背后的原理给出可直接复制的实现再把几个高频坑和排查方法一并交代。适合三类人看不想给中小项目背上Redisson重依赖的Java开发想把分布式锁原理讲透、应对面试的人以及想完全掌控锁行为、不被框架黑盒坑的维护者。1. 为什么还需要一把“轻量级”Redis分布式锁1.1 分布式锁本质要解决什么问题分布式锁解决的是多进程、多实例之间的互斥问题。单机应用里我们用synchronized、ReentrantLock那是因为所有线程都在同一个JVM里竞争的是同一块内存一旦应用拆成多个实例或者多个进程同时操作一份共享资源JVM内部的锁就完全失效了。这时候必须引入一个所有节点都能访问到的“裁判员”让任何一个时刻只有一个客户端能进入临界区。我对分布式锁的要求总结下来就三条硬指标第一是互斥同一时刻只有一个客户端能拿到锁第二是安全持有锁的客户端无论如何都不能导致死锁比如进程崩了、网络断了锁也要能自动释放第三是活性加锁和解锁不能被阻塞住更不能因为某个客户端一直占着锁把其他客户端活活饿死。这三条看起来简单真正落地时每条都能衍生出若干细节。比如“自动释放”依赖锁的过期时间“互斥”依赖加锁命令的原子性“活性”则要求锁必须能及时被释放不能因为持有者没解锁就永久卡死其他请求。写锁的时候脑子里时刻装着这三个指标很多坑就不会踩。1.2 为什么选Redis当锁的中间件用Redis做分布式锁核心原因是Redis的几个天然特质。第一Redis是单线程处理命令的这意味着一条命令在执行过程中不可能被其他命令插队天然就是原子的。SET key value NX PX 30000这样一个命令既完成“不存在才设置”的判断又完成“设置过期时间”的操作整个逻辑由Redis内部一次搞定。后面讲Lua脚本利用的也是同样的单线程特性。第二Redis性能太高了。内存操作加解锁基本是微秒级即使在高并发下每秒几千次的加解锁操作也不会成为瓶颈。对比一下ZooKeeper和etcd这两者也都能做分布式锁但一次操作要经过共识协议性能和Redis差了几个数量级。企业的Redis基本已经普及了不需要为了一把锁再引入一套需要维护的ZooKeeper集群。第三Redis的TTL机制天然适配“崩溃后自动释放”这个需求。持有锁的进程一旦宕机锁到期后自动消失不需要人工介入清理。1.3 常见的锁场景与不该用锁的场景现实中我见过的分布式锁使用场景排前面的是这几类秒杀和抢购的库存扣减多实例部署的定时任务防止重复调度缓存不存在时防止多个请求同时回源打爆数据库异步消息处理时保证同一个业务ID不会被并发消费。但我也见过不少滥用分布式锁的例子。单机应用内部多个线程操作普通变量这个加分布式锁毫无意义用synchronized成本更低。另外如果数据库层已经用唯一索引来保证数据不重复业务代码又加了一把Redis锁这属于重复防御锁万一出了故障反而引入新的复杂度。分布式锁是“尽力而为”的并发控制手段它不能替代数据库约束这类强一致性机制只能作为第一道防线。2. 核心原理一条SET命令和一段Lua脚本2.1 从SETNX到SET NX PX解决“只创建不续命”的死锁早期用Redis做分布式锁最经典的回帖就是SETNX key value搭配EXPIRE key seconds两条命令。先判断key不存在才设置成功后再给key设置过期时间。思路是对的但两条命令之间不是一个原子操作埋了个大雷。设想这个场景线程A执行SETNX lock order:1成功正准备执行EXPIRE lock 30结果进程发生了长时间的GC停顿或者直接被运维kill掉EXPIRE这行代码永远没有执行。这把锁就变成了一个永远不过期的死锁其他所有线程都会被卡死。Redis 2.6.12之后SET命令扩展了NX和EX/PX选项我们终于可以用一条命令完成两件事SET lock:order:1 9f8c7d uuid1 NX PX 30000NX表示key不存在时才设置PX表示过期时间为30000毫秒。不管是进程崩溃还是命令执行到一半断网这条命令要么完整执行要么完全不执行不存在中间状态。2.2 value为什么要用唯一凭证——锁误删问题的源头很多初学者加锁时value直接填一个固定字符串比如locked。这么做在低并发下可能看不出问题但只要锁过期过一次就必然出事。模拟一个真实时间线线程A拿到锁执行任务太慢30秒后锁过期了此时线程B加锁成功value同样是locked线程A终于执行完调DEL lock释放锁把线程B的锁删掉了线程C趁虚而入拿到锁线程B和C同时进入临界区。两个线程同时改同一个库存数据就乱了。解决这个问题的关键是给每一次加锁生成一个唯一凭证通常用UUID加线程ID组合放进value里。释放锁时先取出value确认是自己加的锁才允许删除。这个凭证就像你住酒店时的房卡退房时前台要先核对房卡是不是你这间房的不能拿着一张通用房卡把别人的房间也退了。2.3 释放锁必须用Lua脚本的原因光是“先查value再删key”还不够这里依然有一个并发窗口。线程A执行GET lock确认value是自己的就在这个瞬间锁到期了线程B抢先把锁设置成自己的value线程A接着执行DEL lock又把线程B的锁删了。原因就是GET和DEL是两条独立命令中间可以插入其他客户端的操作。要消除这个窗口必须把“比较删除”这两个动作交给Redis在内部一次性完成这就是Lua脚本的价值if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 endRedis执行Lua脚本时整个脚本是在服务端单线程内跑完的中间不会被任何其他命令打断。这两条Redis命令组合起来就是一个原子操作——先看value是否匹配匹配才删。对比一下数据库里的SELECT ... WHERE之后再做DELETE同样有竞态但数据库有事务可以保证原子性Redis这里就要靠Lua脚本。3. 轻量级方案落地Java实现与关键细节3.1 技术选型用StringRedisTemplate而不是RedisTemplate这个坑我估计一半人都踩过。项目里如果用Spring Data Redis很多人习惯注入RedisTemplateString, Object但默认的序列化器是JDK序列化JdkSerializationRedisSerializer存进Redis的value是一串带着类型信息的二进制。加锁时value写进去是一坨序列化后的字节Lua脚本里拿ARGV[1]跟redis.call(get, KEYS[1])比较时两边内容根本对不上校验永远失败锁永远释放不了。轻量级锁场景下value本身就是一个普通字符串我们应该用StringRedisTemplate它的key和value都走StringRedisSerializer存进去是什么取出来就是什么。不仅代码更清晰也彻底避开序列化器不一致的暗坑。我在本地做验证时用一个Configuration类注入StringRedisTemplate就行不需要任何额外配置Configuration public class RedisLockConfig { Bean public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) { return new StringRedisTemplate(factory); } }3.2 加锁方法tryLock、带重试的lock和阻塞等待加锁的核心方法就一行底层对应SET key value NX PXpublic boolean tryLock(String key, String requestId, long expireMillis) { return Boolean.TRUE.equals(stringRedisTemplate.opsForValue() .setIfAbsent(key, requestId, Duration.ofMillis(expireMillis))); }有人会问opsForValue().setIfAbsent带Duration和不带有什么区别。不带Duration的重载底层发的是SETNX只有创建没有过期时间带Duration的重载在Spring Data Redis 2.x里会组装成完整的SET key value NX PX正好满足我们的一步到位需求。光有tryLock还不够业务里经常需要“等一会儿拿不到锁再说”于是补一个带重试次数的lock方法public boolean lock(String key, String requestId, long expireMillis, int maxRetryTimes, long retryIntervalMillis) { int retry 0; while (retry maxRetryTimes) { if (tryLock(key, requestId, expireMillis)) { return true; } try { Thread.sleep(retryIntervalMillis); } catch (InterruptedException e) { Thread.currentThread().interrupt(); return false; } retry; } return false; }重试时Thread.sleep够用但要把中断异常正确处理掉——重置中断标志后返回失败而不是吞异常继续跑。高并发场景如果等待时间比较长我更推荐用LockSupport.parkNanos做自旋等待线程调度开销比sleep更可控public boolean lockUntil(String key, String requestId, long expireMillis, long maxWaitMillis) { long deadline System.currentTimeMillis() maxWaitMillis; while (System.currentTimeMillis() deadline) { if (tryLock(key, requestId, expireMillis)) { return true; } LockSupport.parkNanos(TimeUnit.MILLISECONDS.toNanos(100)); } return false; }3.3 释放锁与可重入的取舍解锁的规范动作是执行前面那一段Lua脚本而不是直接delete(key)。Spring Data Redis里可以这样封装private static final String UNLOCK_LUA if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(del, KEYS[1]) else return 0 end; public boolean unlock(String key, String requestId) { DefaultRedisScriptLong script new DefaultRedisScript(UNLOCK_LUA, Long.class); Long result stringRedisTemplate.execute( script, Collections.singletonList(key), requestId); return Long.valueOf(1L).equals(result); }使用时务必放在finally里避免异常导致锁残留String requestId UUID.randomUUID() : Thread.currentThread().getId(); boolean locked redisLock.lock(lockKey, requestId, 30000, 3, 200); if (!locked) { throw new BizException(系统繁忙请稍后重试); } try { // 临界区业务 } finally { redisLock.unlock(lockKey, requestId); }至于可重入Redisson默认支持手写的轻量方案默认是不支持的。我实际观察下来绝大多数业务场景里一个线程只需要在方法入口拿一次锁根本用不到可重入真遇到了比如一个加锁方法内部又调用了另一个加锁方法可以用ThreadLocal记录持有次数配合Redis里的Hash结构保存重入计数但这是以牺牲简洁性为代价的。轻量方案讲的就是克制我倾向于“不支持可重入”遇到真的需求再单独加一层ThreadLocal计数器也不晚。3.4 要不要做简易续期看门狗Redisson内置了一个看门狗锁默认30秒后台有一个定时任务每隔10秒检查一次只要业务还没结束就自动续期。轻量方案里如果业务执行时间不可控我建议抄一个简化版——别去依赖框架自己起一个定时任务续期。续期有个细节很容易被忽略不能无脑EXPIRE否则锁已经被别的线程拿走了你这一续期等于给别人续命把别人锁里的value续上了自己的过期时间。所以续期脚本也要带value校验if redis.call(get, KEYS[1]) ARGV[1] then return redis.call(expire, KEYS[1], ARGV[2]) else return 0 end用一个ScheduledExecutorService在加锁成功后启动定时任务每隔expireMillis / 3执行一次续期解锁时取消任务。这里要特别提醒续期线程必须和锁的持有者生命周期绑定否则线程泄漏会把锁的过期时间无限续下去等于绕开了“自动释放”这条安全底线。不过我的个人建议是如果你的业务执行时间基本可控比如最长不会超过500毫秒那把锁的过期时间设置为业务最坏耗时的2到3倍比如设成1500毫秒就完全不需要看门狗。续期机制是兜底方案不是标配多一个组件就多一个故障点能不用就不用。4. 四个真实故障复盘与排查记录4.1 锁被误删为什么value校验不是万能的我线上遇到过一起“库存被多扣”的事故根因就是最经典的锁误删。当时的代码已经做了value校验但用的是先GET再DEL的两段式写法在高并发下出现了竞态窗口线程A校验完value后锁恰好到期线程B拿到锁线程A的DEL把B的锁删了。这个案例给我们的教训很直接value校验本身没错错在“比较”和“删除”没有原子性。改法就是换成Lua脚本把两个动作交给Redis在单线程里顺序执行窗口立刻消失。排查这类问题最快的办法是看Redis的慢日志和客户端日志。redis-cli slowlog get能列出执行时间超过阈值的命令锁误删往往伴随大量DEL命令在很短时间窗口内出现。如果加了Redis的MONITOR监控可以精确看到哪个线程在什么时刻执行了GET和DEL但要小心生产环境MONITOR会拖垮Redis性能只能短时间抓包不要长期开着。4.2 业务执行时间超过锁过期时间锁的过期时间是整个锁生命周期里最需要拿捏的参数。设短了业务还没跑完锁就释放了另一个线程进来重复执行设长了一旦持有锁的线程卡死其他线程要等很久才能拿到锁。我遇到过一个实际案例某业务同步数据预估耗时2秒我给锁设了5秒过期结果那个接口因为一次数据库慢查询跑了整整12秒锁在第5秒就没了另一个实例也进来同步同一批数据两边冲突。这个问题的解法分三步走。第一步给锁过期时间设置一个合理的余量有一个简单的经验公式锁过期时间 业务预估最坏耗时的2~3倍在锁的单元测试里用实际压测数据校准而不是拍脑袋填一个数字。第二步如果业务耗时确实不可控就用上一节说的简易续期机制。第三步也是最容易被忽略的业务侧必须做幂等兜底——哪怕锁真的提前释放了数据库的唯一索引、业务表里的状态机、消息里的幂等号至少有一个能把并发写挡下来。锁防的是大概率事故幂等兜底防的是小概率灾难。4.3 主从切换导致锁丢失之后这是Redis分布式锁被吐槽最多的一类问题我必须把原理讲清楚。Redis主从复制是异步的主节点上执行SET lock:order:1 xxx NX PX 30000成功这条命令会先写进主节点的内存然后异步复制给从节点。如果主节点在命令复制到从节点之前崩溃了哨兵会从从节点里选出一个新的主节点而这个新主节点上根本没有这把锁。此时两个客户端都可能加锁成功锁的互斥性就破了。对这个问题业界有两种主流态度。一种是用Redis官方提出的RedLock算法要求锁在多个独立的Redis节点上加成功才算加锁成功原理是把单点问题分摊到多个节点降低锁丢失概率另一种是分布式系统专家Martin Kleppmann的观点他认为RedLock在时钟跳跃、GC停顿等场景下依然存在一致性漏洞锁的可靠性无法严格保证。我自己看下来这两种观点其实是站在不同量级的需求上说话如果锁的一致性是整个系统的命门那根本不该用Redis如果只是防止多节点重复执行的非资金级操作RedLock的复杂度和运维成本往往超过了收益。工程上我现在的做法是锁仍然用单节点Redis但把它定位成“高概率的互斥控制”后面再放一道数据库幂等约束兜底。真要追求强一致我会直接选etcd或者ZooKeeper它们的锁协议本身就是围绕共识设计的这才是“锁可靠”的正道。4.4 高并发下的command timed out问题日志里看到Redis command timed out; nested exception is io.lettuce.core.RedisCommandTimeoutException这是Lettuce客户端抛出的超时异常。我排查过几次原因不外乎几类锁的tryLock在高并发下批量请求Redis连接池被打满请求一直在排队等待连接或者是Redis执行了阻塞命令比如KEYS *、大Key删除后面的命令全部排队再或者Redis所在机器网络抖动、CPU被打满命令迟迟没有响应。这里有一个很多人忽略的细节分布式锁的加解锁每次都要请求Redis如果客户端异常处理不当超时异常会让锁方法直接抛错而业务代码可能没把这次加锁当成失败处理结果不加锁就进入了临界区。我的代码里tryLock在捕获到超时异常时会返回false让上层走“系统繁忙”的降级逻辑绝不静默继续。连接池和超时参数的调整也很有讲究我当前项目里的配置供参考spring: redis: timeout: 500ms lettuce: pool: max-active: 100 max-idle: 32 min-idle: 8 max-wait: 300mstimeout从默认的60秒降到500毫秒是为了让锁方法快速失败而不是长时间挂住线程。连接池扩到100是压测后得到的值上千并发寸步不让的话这个参数还是要根据业务峰值重新压测。5. Redisson与轻量级方案怎么选我的建议5.1 一张表看清两种方案的区别很多时候选型不是技术高下之争而是使用场景的匹配。我把两种方案的关键差异列了一张表维度Redisson轻量级手写方案API能力可重入锁、公平锁、读写锁、批量锁、红锁只有基础互斥自动续期内置看门狗自实现或设定大超时额外依赖引入整个Redisson jar包零额外依赖行为透明性黑盒出问题要翻源码代码完全可控加锁性能框架有内部优化整体不错命令级直观可控学习门槛会用API容易吃透原理难必须懂Redis命令和Lua故障恢复内置重试和看门狗逻辑全部自己实现适用场景快速接入、锁类型复杂单节点Redis、业务简单、依赖精简5.2 什么时候可以放心动手写我给出的判断标准很简单。第一业务属于中小体量没有多集群多机房这种极端部署第二锁的复杂度低只是拿锁、执行、释放不需要读写锁、公平锁这类花哨能力第三团队能接受锁偶发失效数据库或业务侧有幂等兜底第四你想把分布式锁的原理彻底吃透而不是永远停留在“调库”层面。这几个条件都满足我非常推荐手写一把轻量级锁。这种方案带来的代码透明性是实打实的——线上出了问题打开自己那几百行业务代码就能定位不用翻Redisson几千个类的源码。5.3 什么时候老老实实用Redisson反过来如果你的业务需要多种锁类型比如读写锁、公平锁、红锁或者你完全不想维护续期逻辑希望框架帮你把看门狗、重试、超时这些细节都处理好Redisson就是成熟的选择。它对这些问题的沉淀经过了大量生产环境验证不是个人项目能比的。做一个功能快速迭代的新系统优先选择Redisson这类成熟组件把精力花在业务上这本身也是正确的工程决策。5.4 我踩坑之后的选型印象踩过几次坑之后我对选型有个体会分布式的世界里没有银弹。Redisson不是万能药手写锁也不是原罪关键是知道每一种锁的边界在哪里。Redis锁最大的价值是它在高并发下提供了成本极低的互斥能力足够覆盖绝大多数业务场景但它的边界也很明显就是主从切换时可能丢锁、业务超时时可能提前释放。这两条边界一旦认下来你的系统设计自然就会补上幂等这道第二防线锁就能安心地工作在最前面。这个内容后续还可以扩展的方向是把加锁操作做成一个注解驱动的AOP工具让业务代码只暴露一个RedisLock(key #orderId)锁的获取、释放、异常处理全部内聚在切面里代码会清爽不少。我在自己的项目里已经这么用了后面有机会再单独写一篇展开聊。

相关新闻

UnionFS与OverlayFS深度解析:从分层原理到实战踩坑

UnionFS与OverlayFS深度解析:从分层原理到实战踩坑

搞容器和Linux系统的人,几乎都绕不开UnionFS和OverlayFS这两个名字。尤其是做Docker镜像分层、系统启动时做只读根文件系统合并、或者想搞一套轻量级系统更新方案的时候,这两个东西总会被摆在台面上。网上讲这两个概念的教程不少,但大多停留在…

2026/10/9 5:57:56 阅读更多 →
AI浪潮下测试者生存法则:构建人类不可复制的三重壁垒

AI浪潮下测试者生存法则:构建人类不可复制的三重壁垒

AI浪潮下的测试者生存法则:人类不可复制的三重壁垒这两年AI的发展速度,说实话让我这个干了十多年测试的老兵都有点后背发凉。从最早的自动化脚本、智能用例生成,到现在的AI agent能自主执行回归测试、自动定位缺陷、甚至生成测试报告&#xf…

2026/10/9 5:57:56 阅读更多 →
GitHub Actions安全加固:应对供应链攻击与脚本注入

GitHub Actions安全加固:应对供应链攻击与脚本注入

大概去年夏天,一个朋友半夜给我发来告警截图:CI日志里赫然打印着云厂商的临时凭证,而这些凭证来自一个第三方Action的“更新”。查到最后,问题不在代码逻辑,而是workflow用了可变tag、没有最小权限,同时把P…

2026/10/9 5:57:56 阅读更多 →

最新新闻

生产级Coding Agent调优实战:Harness工程化决定落地下限

生产级Coding Agent调优实战:Harness工程化决定落地下限

1. 从"能跑"到"好用":生产级 Coding Agent 的最后一公里到底卡在哪Vibe Coding 这个词这两年被聊得很多,大意是开发者用自然语言描述意图,让 Coding Agent 去生成、修改、验证代码,人只负责把握方向和验收。听…

2026/10/9 6:35:27 阅读更多 →
Java Swing人事管理系统:JDBC+MySQL课程设计实战与避坑指南

Java Swing人事管理系统:JDBC+MySQL课程设计实战与避坑指南

简介:这份资源是一套基于 Java Swing、JDBC 与 MySQL 实现的人事管理系统课程设计项目,面向正在完成数据库课程设计、需要可运行参考案例的计算机相关专业学生。项目包含可视化软件界面,覆盖人员信息维护、数据库连接与增删改查等典型业务场景…

2026/10/9 6:35:27 阅读更多 →
MySQL校对规则:utf8mb4_general_ci与utf8mb4_bin的差异及选型

MySQL校对规则:utf8mb4_general_ci与utf8mb4_bin的差异及选型

1. 这两个校对规则到底在吵什么看你一脸问号地点进来,我猜你多半是遇到过这种情况:建表的时候复制了一段别人的SQL,里面有CHARSETutf8mb4 COLLATEutf8mb4_general_ci,或者是utf8mb4_bin,当时也没多想,能用就…

2026/10/9 6:35:27 阅读更多 →
PS5底层开发合规边界与技术可行性分析

PS5底层开发合规边界与技术可行性分析

我无法根据当前输入生成符合要求的博文。原因如下:项目标题 "AnyPS5" 缺乏明确指向性:该词在公开技术语境中无公认定义,既非官方产品名(索尼未发布/命名过 AnyPS5)、非开源项目(GitHub、GitLab、…

2026/10/9 6:35:27 阅读更多 →
claude-mem:为Claude Code打造跨会话长期记忆的实战指南

claude-mem:为Claude Code打造跨会话长期记忆的实战指南

用过 Claude Code 写真实项目的人,基本都遇到过这个场景:昨天刚跟 AI 讨论清楚的一个架构方案,今天新开一个会话,它完全不记得了。你在同一个仓库里翻历史对话记录,发现上一个会话已经把项目的来龙去脉都喂给了它&…

2026/10/9 6:35:27 阅读更多 →
Agent-Reach:LLM API智能路由与成本可控调度中枢

Agent-Reach:LLM API智能路由与成本可控调度中枢

1. 项目概述:Agent-Reach 是什么?它解决的不是“能不能用”,而是“怎么用得稳、用得准、用得省”Agent-Reach 这个名字乍看像某个开源模型或工具库,但结合 CLI、API、YouTube、Reddit 这些高频热词,再叠加上“zcode cl…

2026/10/9 6:34:27 阅读更多 →

日新闻

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API实战:LocalDate、Date与ZonedDateTime的转换与避坑指南

Java时间API这个话题,隔三差五就会在群里被翻出来讨论一次。上周还有个同事线上处理一个订单超时问题,排查到最后发现是ZonedDateTime序列化后时区丢了,用户在下单当天晚上看到的时间整整差了8个小时。这类问题几乎每个做Java开发的人都遇到过…

2026/10/9 0:00:49 阅读更多 →
EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

EasyTier实践:从NAT穿透到子网代理的异地组网部署与排错

前几个月我手头有好几台机器需要互相访问:办公室台式机、家里 NAS、还有一台云主机。如果只是偶尔传个文件倒还好,问题是工作场景经常要在几处环境之间来回切换,每次都先登录跳板机再层层代理,实在折腾。我先后试过端口映射、自建…

2026/10/9 0:00:49 阅读更多 →
AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent工程实战:从七要素到七个决策点的系统设计指南

AI Agent 这个词在过去一年里被反复提及,但真正动手搭过一套能跑起来的 Agent 系统的人都知道,从"知道它是什么"到"让它稳定干活"之间隔着一整套工程决策。我前后参与过几个 Agent 项目的落地,从最初用现成框架拼装&…

2026/10/9 0:01:50 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:32 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:40 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 10:10:36 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 21:13:17 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/8 15:26:17 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/9 6:17:20 阅读更多 →