知其然,知其所以然
Java 内部原理 2026-10-02

虚拟线程:Java 21 如何让一个线程对应一个任务

JDK 21 虚拟线程实测:10000 个各 sleep 1 秒的任务,虚拟线程 1073 ms 完成、RSS 85 MB;每任务一个平台线程在第 4059 个任务时因 unable to create native thread 失败;200 线程池要 50358 ms;纯计算任务虚拟线程没有优势;2000 个虚拟线程只用了 10 个载体线程。

Java 虚拟线程 Java 21 并发 真实验证 动画演示
Java 内部原理 2026-10-02

虚拟线程 Pinning:什么情况下仍然会卡住载体线程

载体线程限制为 2 个时,10 个虚拟线程各阻塞 500 ms:JDK 21 上 synchronized 里阻塞要 2548 ms(被固定、分 5 批),ReentrantLock 与无锁都只要约 520 ms;JDK 27 上三种都约 519 ms;用 -Djdk.tracePinnedThreads=full 看固定发生的栈。

Java 虚拟线程 pinning synchronized 真实验证 动画演示
Java 内部原理 2026-10-02

CompletableFuture 超时与取消:任务到底能不能停

真实验证 CompletableFuture 的超时与取消:orTimeout 超时后任务从 4 步继续跑到 15 步,cancel(true) 不中断任务,依赖阶段抛 CompletionException(cause 为 CancellationException);executor.submit 的 Future.cancel(true) 才能中断任务,并可与 CompletableFuture 组合;completeOnTimeout 与 get(timeout) 的语义差别。

Java CompletableFuture 超时 取消 并发 真实验证 动画演示
Java 内部原理 2026-10-02

反射与 MethodHandle:一个方法调用如何变成调用点

真实验证 MethodHandle:invokeExact 的类型必须完全一致、invoke 自动适配、bindTo 绑定接收者、访问检查在查找时发生;static final 的 MethodHandle 与直接调用一样快(0.31 ns),放在非 final 字段里慢到 2.34 ns,Method.invoke 是 2.76 ns。

Java MethodHandle 反射 invokeExact 真实验证 动画演示
Java 内部原理 2026-10-02

动态代理:JDK Proxy 和代理调用链怎么生成

真实验证 JDK 动态代理:代理类是 public final 的 jdk.proxy1.$ProxyN,toString/hashCode/equals 也进 handler;handler 里直接 m.invoke 会让目标的 IOException 变成 UndeclaredThrowableException;default 方法要 invokeDefault;代理调用约 3.28 ns(直接 0.35 ns);并把生成的代理类导出来看字节码。

Java 动态代理 Proxy InvocationHandler 真实验证 动画演示
Java 内部原理 2026-10-02

注解:Retention、反射和运行时代理

真实验证注解的运行时形态:注解实例是 $ProxyN 代理对象、同一注解读两次是同一对象;@Inherited 只沿父类继承,接口和方法注解不继承;重复注解被包进容器后 getAnnotation 读到 null;CLASS/SOURCE 读不到;TYPE_USE 注解要走 getAnnotatedType;第一次 getAnnotation 约 12 ms;并用 javap 看注解在类文件里的位置。

Java 注解 反射 Inherited Repeatable 真实验证 动画演示
Java 内部原理 2026-10-02

ServiceLoader:Java SPI 如何发现实现类

真实验证 ServiceLoader:META-INF/services 里的顺序就是迭代顺序、load 与 stream 不实例化、迭代时才构造并缓存、reload 清缓存;配置出错在迭代到该项时抛 ServiceConfigurationError;模块方式用 provides/uses,module-path 里没有 impl 时找不到实现也不报错。

Java ServiceLoader SPI 模块系统 真实验证 动画演示
Java 内部原理 2026-10-02

Spliterator:Stream 如何拆分数据源

真实验证 Spliterator:各数据源的特征位(ArrayList 是 ORDERED SIZED SUBSIZED,filter 之后只剩 ORDERED);trySplit 的拆法(ArrayList 对半、LinkedList 按 1024 递增的批);自定义 Spliterator 拆不动时并行流只用 1 个线程、耗时 658 ms,可拆时 10 线程 107 ms。

Java Spliterator Stream 并行 真实验证 动画演示
Java 内部原理 2026-10-02

ByteBuffer:堆内、堆外和 Direct Memory

真实验证 ByteBuffer:堆内有数组、堆外没有;slice 共享内容;分配 1 MB 堆外比堆内慢几倍(100 vs 21 µs);写 512 MB 文件的耗时在堆内与堆外之间交叠;堆外内存丢引用后不立刻释放,要等 GC;MaxDirectMemorySize=64m 时在 64 MB 后抛 OutOfMemoryError(与堆无关)。

Java ByteBuffer 堆外内存 Direct Memory NIO 真实验证 动画演示
Java 内部原理 2026-10-02

Metaspace:类元数据为什么会把进程撑爆

真实验证 Metaspace:定义 5000 个类使 Metaspace 涨约 9965 KB;MaxMetaspaceSize=24m 时 7962 个类后抛 OutOfMemoryError: Metaspace;类不可达后要 GC 才卸载(5000 个类、Metaspace 从 10704 KB 降到 911 KB);默认 MaxMetaspaceSize 无上限。

Java Metaspace 类元数据 类卸载 真实验证 动画演示
Java 内部原理 2026-10-02

ZGC:几乎低停顿是怎么做到的

在 JDK 21 上用同一个负载比较:存活集 400 MB 时 Parallel 最长间隔 260.54 ms、G1 88.6 ms,而 2 GB 堆的 ZGC 只有 0.49 ms;但把 ZGC 堆缩到 1 GB 时出现 84 行 Allocation Stall、最长间隔 85.43 ms;ZGC 一次回收只有 3 次 0.01 ms 级的停顿,标记与搬迁都是并发的。

Java ZGC 垃圾回收 低停顿 真实验证 动画演示
Java 内部原理 2026-10-02

Shenandoah:并发整理如何避免长暂停

JDK 21 上同一负载:Shenandoah 日志里最长停顿 0.195 ms(G1 是 88.734 ms 且有 6 次 Full GC),没有退化回收;但程序自己看到的最长间隔仍有 26.34 ms(2 GB)、30.08 ms(1 GB),超过 5 ms 的间隔比 G1 还多;并看一个并发周期的阶段。

Java Shenandoah 垃圾回收 低停顿 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号