Skip to content
  • AQS 原理详解:ReentrantLock 底下的那套排队框架

    学了 ReentrantLock、读写锁、SemaphoreCountDownLatch 之后,可能有过一个疑问:这一堆工具,底层是不是各写各的?不是,它们底下全是同一个东西——AQS(AbstractQueuedSynchronizer,抽象队列同步器)。JUC 里大半的同步工具,都是在这一个框架上搭出来的。这篇把它拆开看:state 是什么、队列怎么排、线程怎么挂起又怎么被唤醒。理解了 AQS,上面那一堆工具就不再是几个孤立的 API,而是同一套机制的不同用法。

    上游文章:《[ReentrantLock 详解](/ful

  • 读写锁详解:ReentrantReadWriteLock 与 StampedLock

    ReentrantLocksynchronized 有个共同点:同一时刻只允许一个线程进。可大量场景里,读和读之间根本不冲突——十个线程同时读一份配置、一个缓存被反复查询,互不干扰,凭什么排队?读写锁就是为"读多写少"准备的:读和读共享,只要有写就互斥。这篇梳理读写锁的规则、锁降级,以及 JDK 8 加的进阶版 StampedLock(乐观读,连读锁都可以不加)。

    锁的全景地图在《锁的分类与实现原理》,`R

  • ReentrantLock 详解:比 synchronized 多给了什么

    synchronized 日常够用了——简单、自动加锁释放,JDK 1.6 之后性能也优化得很好。但它有几个天生的限制:拿不到锁就一直傻等、等的时候不能被中断、所有线程抢锁不排队、也没有办法让线程"分拨"等待。这篇把 ReentrantLock 系统梳理一遍:它补齐了哪些能力、每个能力解决什么场景,以及什么时候其实还是 synchronized 更合适。

    这是"锁"系列的一篇。各种锁概念的全景(本地锁/分布式锁/悲观乐观锁)在《[锁的分类与实现原理](/software-architecture/design-ideas/lock-o

  • Android 混淆规则文件 proguard-rules.pro 详解(keep 指令与 R8 工作流)

    release 包出问题,排查到最后基本都会翻到这个文件——proguard-rules.pro。规则写得对不对,直接决定线上会不会闪退。这个文件本身机制不复杂:R8 对代码做四件事——压缩、优化、混淆、预检,keep 规则就是告诉它「这几处别碰」。但「别碰」有四种说法,选错一种线上就崩。这篇把规则文件系统梳理一遍:它怎么被加载、keep 四兄弟的区别、什么必须 keep、出了事怎么用 mapping 反推。

    一、规则文件在构建里扮演什么角色

    它就放在 app/proguard-rules.pro,自己不干活——它只是 R8

  • IM 即时通讯系统架构分析与 Spring Boot 实现

    一、先看需求本质:服务端要“主动”找人

    IM,Instant Messaging,即时通讯——微信单聊、客服对话、App 里的系统通知,都属于这一类:消息要在“发出去”和“被看到”之间几乎无延迟地送达

    平时用微信,消息不丢、不重、一问一答顺序稳定,感觉理所当然。可真要自己动手做一个 IM(比如给产品加个客服聊天),把链路拆开才发现处处是坑:消息发出去了,对面可能没收到;超时重发,对面会收到两条一样的;走不同网络路径的消息,还可能后发的先到。

    这三个现象分别对应 IM 系统的三件核心事:不丢、不重、不乱序。这篇把 IM 系统

  • 缓存与数据库一致性:从 Cache Aside 到 binlog 订阅

    先看一个典型的缓存事故:用户改了头像,刷新好几遍还是旧头像。查缓存 TTL,60 秒早该过期了——最后发现是更新顺序出了问题:先删了缓存,数据库还没改完,另一个线程又把旧数据读回缓存。缓存和数据库的不一致,就是这么不经意间产生的。

    这篇把缓存一致性从最基础的 Cache Aside 讲到 binlog 订阅:为什么会出现不一致、延迟双删在防什么、Canal 怎么把缓存操作彻底解耦。代码按 Spring Boot 落地。


    一、先定基调:Cache Aside(旁路缓存)是基础

    先理清读写姿势,绝大多数不一致都是**姿

  • 分布式任务调度:从 @Scheduled 到 SnailJob(防重实战)

    一个很常见的架构演进坑:业务里定时任务一堆——每天凌晨备份数据库、每小时同步对账、每分钟刷新报表缓存,最早一个 @Scheduled 就能搞定;可服务从单机扩到多实例后,问题来了——凌晨的备份任务被三个实例同时执行,数据库被锁死,备份文件也错乱

    这就是分布式环境里定时任务的第一大坑:多实例重复执行。这篇从 @Scheduled 出发,按演进顺序讲:为什么多实例会重复执行、Redis 锁怎么防重、以及专业调度框架(XXL-Job / SnailJob)解决哪些锁解决不了的问题。代码按 Spring Boot 落地。


  • 分布式事务:从本地消息表到 Seata(下单链路演进)

    想象这个场景:凌晨两点报警响起——下单服务成功扣了库存,但订单服务超时了,积分也没加上。用户没买到东西,库存却少了。系统拆成多个服务多个库之后,这种"一半成功一半失败"的事故就注定会来:单个数据库里靠事务就能原子提交,拆开了,@Transactional 就管不到了。

    这就是分布式事务要解决的问题。这篇按演进顺序把方案捋一遍:本地消息表 → 事务消息 → TCC → Seata AT。每一版解决什么、代价是什么,最后给你一张选型表。代码按 Spring Boot 落地。


    一、问题先讲清楚:跨库事务为什么难

    下单

  • 接口幂等与防重提交:从数据库唯一键到状态机

    先看一个经典的翻车现场:用户在支付页面手抖点了两下提交,前端发了两个一模一样的 POST,两个请求都进了支付流程——订单重复,扣了两次款。这就是典型的重复提交,而背后是更普遍的问题:接口幂等

    幂等这词听着唬人,本质就一句话:同一个操作,执行一次和执行一百次,结果一样。支付回调、表单提交、消息消费,这三类场景天天跟它打交道。这篇把幂等的方案从简单到可靠排一遍:为什么唯一键够用、什么时候必须上状态机、消息重复消费怎么兜底。代码按 Spring Boot 落地,能实跑的我都实跑验证过。


    一、先分清:哪些请求天生幂

  • 订单超时自动关闭:延迟消息的四种实现

    一个看起来很小的需求:用户下单 15 分钟没付款,订单要自动关闭、库存要释放。实现方式却五花八门:定时轮询、Redis 过期通知、RabbitMQ 死信队列、延迟插件、时间轮……最常见的起点是定时任务每分钟扫一次表,但数据量上来之后,扫一次要好几秒,还经常把数据库拖慢。

    这篇把"延迟任务"的四种主流实现从简单到可靠排一遍:定时轮询 → Redis 过期通知 → RabbitMQ 死信/延迟队列 → 时间轮。每种讲清原理、代码和坑,最后给选型表。代码按 Spring Boot 落地。


    一、先看需求本质:这是一个"延迟任务"问题