在 JDK 21 上实测 ThreadFactory 决定的线程身份:new Thread 继承创建者的 daemon / 优先级而 defaultThreadFactory 不继承;submit 抛异常不进入 UncaughtExceptionHandler,execute 抛异常会换线程;池线程拍下首次提交者的 context ClassLoader 与 InheritableThreadLocal;非 daemon 池让 JVM 5 秒不退出;线程是惰性创建的(0 → 1 → 2 → 2 → 2 → 3 → 4)。
在 JDK 21 上实测 CompletableFuture 的异常:同一个异常在 handle / join / get / exceptionally 里的形状(CompletionException、ExecutionException、原始异常)不同;没人观察的异常不产生任何输出;whenComplete 里再抛的异常被丢掉;allOf 在 100 ms 失败后仍等到 1006 ms 才抛出;cancel 与 orTimeout 不会停止底层任务。
用 GraalVM CE 25.0.2 的同一个 JDK 比较 C1 / C2 / Graal JIT:分支内逃逸的对象 C2 与 Graal 都被消除、关掉 PEA 后 Graal 不再消除;原以为 Graal 能消除的“同一对象罕见分支逃逸”两者都没消除;5 个小负载里 C2 有 4 个更快;稳态 stream 每批 24 ms vs 31 ms;峰值内存 205 vs 250 MiB。
用 GraalVM CE 25.0.2 的 native-image 实测:Hello 构建约 15.8 s、可执行文件 12.3 MiB,启动 5 ms vs JVM 40 ms、内存 9.3 vs 99.6 MiB;反射需要登记(agent 生成配置),未登记的类 ClassNotFoundException;--initialize-at-build-time 把静态状态冻结进镜像;吞吐上 stream 只有 JIT 的 1/3–1/4,hash 反而最快。
用 jcmd Compiler.queue 在 JDK 21 上观察 JIT 编译队列:3000 个小方法的洪水下 C2 队列最长 9、同时编译 3 个(C1 队列始终为空);CICompilerCount 从 2 到 8 总用时 1861 → 1666 ms;-Xbatch 预热慢近 2 倍(1739 vs 898 ms);没有观察到热点方法被队列拖慢。
在 macOS arm64 的 JDK 21 上量对象分配速度:默认 AllocatePrefetchStyle = 1、Distance = 384;各 style 之间的差异与同一配置三次运行的波动同量级;Distance = 512 对 64 字节差 23%、对 1 KiB 好 40%;小对象约 2 ns 与大小无关;多线程总带宽不线性增长且包含 GC。
在 JDK 21 / macOS 上实测 Shutdown Hook:正常返回、System.exit、未捕获异常、SIGINT / SIGTERM / SIGHUP 会运行(退出码 130 / 143 / 129),Runtime.halt 与 kill -9 不会;多个 hook 并发且顺序不定;SIGTERM 后 1 秒 kill -9 只完成 3 / 10 步清理;hook 里 System.exit 不退出、addShutdownHook 抛异常。
在 JDK 21 上实测退出码:System.exit(256) 是 0、300 是 44、-1 是 255;子线程的未捕获异常不改变退出码;两个线程各 exit 的结果 18 / 12 随机;ExitOnOutOfMemoryError 的退出码是 3,默认 OOM 在子线程发生时进程继续并以 0 退出;java 启动器各类错误都是 1。
在 JDK 17 / 21 / 27 上实测 sun.misc.Unsafe 与替代方案:JDK 27 默认打印 terminally deprecated 警告,deny 时抛异常;objectFieldOffset 对 record 与隐藏类抛 UnsupportedOperationException;MemorySegment / VarHandle / ByteBuffer 与 Unsafe 的读写都约 0.5 ns;VarHandle 与 Unsafe 的 CAS 成本相同;Unsafe 不 free 的 412 MiB 在 gc 后仍在,Arena 有边界与生命周期检查。
在 JDK 21 上实测 Files.mismatch:返回第一个差异的下标、前缀返回较短长度、相同返回 -1;耗时与需要比较的字节数成正比(差异在开头 0.1 ms、在末尾 40.9 ms,128 MiB);比 readAllBytes + Arrays.equals 少分配 213 MiB、比 SHA-256 快 3.6 倍;大小不同、前缀相同时仍然要读完较短的文件。
在 JDK 21 / macOS 上用两个 JVM 实测 FileChannel.lock:tryLock 返回 null、lock() 阻塞 1934 ms、共享与区域锁的规则;同一 JVM 内重叠抛 OverlappingFileLockException;锁只是建议性的(B 不申请锁照样写入);kill -9 后立即释放,但关闭同进程内同文件的另一个通道会丢锁(isValid 仍为 true);锁文件被删除后两个进程都拿到锁。
在 JDK 21 上实测 AsynchronousSocketChannel:完成回调运行在线程组的线程上;数据已就绪时回调会直接嵌套调用 16 层(sun.nio.ch.maxCompletionHandlersOnStack 默认值,设 0 后栈深度恒为 11);每个通道只能有一个未完成的 read 与 write;write 只写出 319 KiB 就完成;读超时之后通道不可再读;未关闭的 accept 通道会让线程组无法终止。