在 JDK 27 上用 java.lang.classfile 解析、从零生成和转换 class 文件:列出指令与代码元素;生成含分支的方法并自动带 StackMapTable;给每个方法入口插入 println(467 → 669 字节);DROP_STACK_MAPS 导致 VerifyError;JDK 21 没有这个包。
真实运行 Phaser:onAdvance 在每个阶段结束时回调并可返回 true 终止(终止后阶段号为负数);运行中 register 与 arriveAndDeregister;超时与中断不会破坏 Phaser(CyclicBarrier 会 isBroken);64 线程下平铺与分层每轮 178.7 vs 177.8 μs,没有可测量差别。
真实运行 Exchanger:两个线程同时返回并互换对象引用;超时与中断后可继续使用;多线程共用时两两配对,奇数个会有一个落单;交换 1024 元素缓冲区传 2048 万个 int 每轮 13–56 ms,逐个元素的 LinkedBlockingQueue 约 1950 ms。
真实运行 LockSupport:许可最多一个、不累加,先 unpark 再 park 立刻返回,而先 notify 再 wait 会丢通知;unpark 到 park 返回中位 1.9 μs;park 遇到中断标志立刻返回,错误的循环写法 200 ms 空转 3239916 次;用 park/unpark 写一个 FIFO 互斥锁并与公平 ReentrantLock 对比。
用 AbstractQueuedSynchronizer 写不可重入互斥锁、信号量、闩锁和带 Condition 的有界缓冲区并运行验证:共享模式一次释放唤醒所有等待者;非公平与公平 tryAcquire 的吞吐 155,738,178 对 155,738,178;await 完全释放锁、signal 把线程移到锁的等待队列。
真实运行 ForkJoinPool.managedBlock:16 个阻塞 100 ms 的任务普通阻塞 432 ms、managedBlock 110 ms(线程 17);maximumPoolSize 小于需要时 managedBlock 抛 RejectedExecutionException;CompletableFuture.join、Phaser、CyclicBarrier、LinkedBlockingQueue.take 会补偿,CountDownLatch、Semaphore、ReentrantLock 不会。
用 WeakReference 验证 ThreadLocal 导致的类加载器泄漏:值是插件类的实例时线程池线程活着就不能回收,值是 String 或卸载前 remove() 就能回收;过期条目的 40 MB 在 GC 后仍占 42 MB 直到被清理;InheritableThreadLocal 在池线程复用时看到旧值。
真实验证并发容器的弱一致性:遍历时修改 ArrayList/HashMap 抛 CME 而并发容器不抛;并发写入时 ConcurrentHashMap 的遍历数到的条目数在 -1000 到 1048 之间,size() 却始终合理;转账求和有 79% 的读取不一致;CopyOnWriteArrayList 是快照但 add 随大小线性变慢。
用 -Xlog:safepoint 看 JDK 21 的安全点:一个小程序 25 次安全点,到达安全点通常只要几微秒;去掉计数循环里的安全点检查后 Thread.getAllStackTraces() 从 0 ms 变成约 1100 ms、System.gc() 变成 1066 ms;getThreadInfo 也是全局安全点;空闲 JVM 没有周期性安全点。
用 -Xlog:gc+tlab=trace 和分配基准看 TLAB:有 TLAB 时 1/8 线程的小对象分配 194/596 M 对象/秒,-XX:-UseTLAB 只有 13/3;TLAB 随线程数自适应变小;-XX:TLABSize=64k 使吞吐降到 132 M/秒;TLABSize=4m 被 JVM 拒绝。
用每次迭代分配的字节数验证 C2 逃逸分析:不逃逸的 24 字节对象默认 ≈0 字节而关闭 EA 后 24 字节;只在 1/1024 的路径上逃逸就消除不了;大方法、int[100]、List 迭代器、Optional 链没被消除;局部装箱、StringBuilder、锁被消除。
验证压缩指针:-Xmx 到 31900m 默认开启、32g 起关闭,对象对齐 16 时上限 64g;对象大小开启与关闭对比(Node 32/40/48 字节);500 万个节点堆占用 155 MB 对 194 MB;JDK 27 默认紧凑对象头使 new Object() 只有 8 字节、堆占用 117 MB。