《Java 高级编程》4.3 锁与条件队列:synchronized、ReentrantLock 与 AQS
libraryd 需要一条借阅等待队列:没有可借副本时让请求有序等待,有人归还时唤醒其中一个。本节用超时、中断、条件队列三组实验对比 synchronized 与 ReentrantLock,手写一个基于 AQS 的 BooleanLatch,并给出 LoanWaitQueue 的完整实现与边界。
tag
libraryd 需要一条借阅等待队列:没有可借副本时让请求有序等待,有人归还时唤醒其中一个。本节用超时、中断、条件队列三组实验对比 synchronized 与 ReentrantLock,手写一个基于 AQS 的 BooleanLatch,并给出 LoanWaitQueue 的完整实现与边界。
8 个线程各增 100 万次,普通 long 只数到 333 万。本节用真实计数实验比较 AtomicLong 与 LongAdder 的吞吐与适用面,手写一遍 CAS 循环,再用 Treiber 栈复现 ABA 并给出 AtomicStampedReference 的修法,最后落到 libraryd 的 LoanCounters 与 LoanMetrics。
libraryd 的缓存刷新线程写了新值,请求线程却一直读旧的。本节用停止标志与 Dekker litmus 两组可复现实验,量化可见性与重排序,讲清 happens-before 的六条规则,再落到 LifecycleFlag 与 AvailabilityCache 的 volatile 发布写法。
libraryd 想在不改 LibraryService 源码的前提下测量 borrow 耗时,Java Agent 是最小侵入的入口。本节实现 Premain-Class 与 Can-Retransform-Classes 清单,用 Byte Buddy 1.18.16 的 Advice 在方法进出打点,真实运行 -javaagent 并读取 agent: borrow took N µs。
第 3 章要改写 libraryd 的字节码,第一步不是选库,而是读懂编译器到底生成了什么。本节用 javap -c -p -v 拆开 FineCalculator 的常量池、栈机器指令和 invokedynamic,再用 ASM 9.11.1 统计方法指令、用 Byte Buddy 1.18.16 生成子类,并给出两者的选择边界。
libraryd 的 ISBN 校验规则要允许客户以 jar 形式追加,不能每次改规则都重新打包整个服务。本节从三层类加载器与双亲委派讲起,实现 PluginClassLoader 的 findClass 与 findResources,用 META-INF/services 和 ServiceLoader 真正加载一次插件 jar,并记录类加载器身份。
libraryd 的每个仓储写方法都包着 begin/commit/rollback,复制到第三个实现时已经很难保持一致。本节用 JDK 动态代理把 TransactionManager.inTransaction 接到仓储接口上,处理默认方法、Object 方法和受检异常,并说明为什么代理只能代理接口、自调用为什么会绕过它。
libraryd 的借阅方法既要记审计,又要在目录服务短暂超时时重试,手写 try/catch 会把业务代码淹掉。本节定义 @Audit 与 @Retry 两个运行时注解,用反射读取 action 与重试参数,实现一个带退避的调用器,并说明保留级别、默认值和幂等性边界。
libraryd 的审计日志不想为 Book、Member、Loan 各写一套字段提取代码,反射是把它做成一个通用组件的最小代价。本节从 Class 的三种来源讲到 Method 查找、invoke 调用、构造器创建,再落到 trySetAccessible 与模块边界,最后给出可用于 record 的字段映射实现。
libraryd 的 JSON 层要反序列化 Page<Book>,但 Page.class 只保留原始类型,Book 这个实参在运行时已经消失。本节用真实编译错误说明擦除的边界,实现一个基于匿名子类的 TypeRef,并把 Page<Book>、Map<String, List<Book>> 的类型令牌接到接口响应解码上。
libraryd 的查询 API 一旦同时接受 Book 和子类型、又要往集合里写回结果,就会撞上泛型不变性。本节用数组协变与 ArrayStoreException 做对照,按 PECS 拆解 extends 与 super 的读写方向,并把 Page 映射、批量保存和过滤谓词的签名落到仓储端口上。
libraryd 的仓储接口从每个实体一份复制粘贴,收敛到 Repository<T, ID>。本节解释两个类型参数各自约束什么、有界类型参数如何把可比较性写进签名、编译器生成的桥方法从哪来,并用 javap 看清擦除后的真实字节码,最后给出泛型仓储的边界清单。
《Java 高级编程》全书导航页:说明卷三在四卷本中的位置、读者画像与前置知识,给出机制补课、改造 libraryd 与排障速查三条学习路径,并按四个部分列出 9 章 27 节的完整索引、项目改造状态、版本依赖与验证方式,另附序、前言和附录 A–D。
交代本书的读者对象、前置知识与九章结构,列出 JDK 25、Maven、Docker 与 clang 的环境清单和真实版本输出,说明代码、实验与命令的书写约定、三种验证层次,以及版本不一致时从 JDK、预览开关、模块路径到本地库的六步排查顺序。
说明卷三为什么在能跑的服务之后还要单独讲语言机制,交代类型系统、运行时、并发与平台性能四个层次,与卷四 JVM 调优和 Spring Boot 卷的分工,并列出 JDK 25 中 synchronized 不再 pin 虚拟线程、ScopedValue 正式、StructuredTaskScope 仍是预览等版本边界,以及三条阅读路径与代码验证方式。