真实验证 Spliterator:各数据源的特征位(ArrayList 是 ORDERED SIZED SUBSIZED,filter 之后只剩 ORDERED);trySplit 的拆法(ArrayList 对半、LinkedList 按 1024 递增的批);自定义 Spliterator 拆不动时并行流只用 1 个线程、耗时 658 ms,可拆时 10 线程 107 ms。
真实验证 ByteBuffer:堆内有数组、堆外没有;slice 共享内容;分配 1 MB 堆外比堆内慢几倍(100 vs 21 µs);写 512 MB 文件的耗时在堆内与堆外之间交叠;堆外内存丢引用后不立刻释放,要等 GC;MaxDirectMemorySize=64m 时在 64 MB 后抛 OutOfMemoryError(与堆无关)。
真实验证 Metaspace:定义 5000 个类使 Metaspace 涨约 9965 KB;MaxMetaspaceSize=24m 时 7962 个类后抛 OutOfMemoryError: Metaspace;类不可达后要 GC 才卸载(5000 个类、Metaspace 从 10704 KB 降到 911 KB);默认 MaxMetaspaceSize 无上限。
在 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 级的停顿,标记与搬迁都是并发的。
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 还多;并看一个并发周期的阶段。
用 lib、app、other 三个真实模块验证模块封装:未导出的包编译期就 not visible;exports … to 只对指定模块开放;反射访问未导出的包抛 IllegalAccessException,opens 的包可以 setAccessible;--add-opens 可临时打开;JDK 的 java.base 有 54 个无限制导出包、67 个限定导出包。
用 javap -v 验证 class 文件:魔数 cafebabe、JDK 21 的 major 65;一个只有 main 的类常量池有 84 项(Utf8 42 项为主);重复字面量只存一份、小整数不进常量池;static final 常量被编译进使用方,只重编译常量所在的类时使用方仍是旧值;字符串常量超过 65535 字节 javac 报错。
用 ASM 生成带自定义 bootstrap 的 invokedynamic:每个调用点只在第一次执行时链接;MutableCallSite 的 setTarget 换目标而不重新链接;bootstrap 抛异常得到 BootstrapMethodError 且失败也被缓存;javap 看调用点与 BootstrapMethods 在类文件里的结构。
真实验证 Semaphore:许可数 1/3/6 时 12 个任务的最大并发是 1/3/6、耗时 1279/433/218 ms;release 不检查上限(Semaphore(2) release 3 次变成 5);没有所有者,别的线程可以 release;Semaphore(0) 可当信号;排队线程先进先出。
真实验证 BlockingQueue:满队列上 offer 返回 false、add 抛 IllegalStateException、put 阻塞(线程 WAITING,park 在 AQS 条件队列里);空队列上 poll 返回 null、remove 抛 NoSuchElementException、take 阻塞;五种队列的吞吐(SynchronousQueue 只有约 0.41 百万次/秒);毒丸、drainTo、PriorityBlockingQueue。
真实验证 ConcurrentLinkedQueue:迭代器弱一致、不允许 null、不阻塞;size() 是遍历(1,000 个 2,099 ns → 1,000,000 个 2,648,479 ns)而 isEmpty() 不是;每个生产者内部保持先进先出;在高度竞争、近乎空的队列上吞吐随线程数从 88.4 降到 8.7 百万次/秒,低于同负载的 LinkedBlockingQueue。
真实验证 IdentityHashMap:内容相同的两个 String 是两个键(HashMap 只有一个),装箱 Integer 100 同一个对象、1000 不同;内部是键值相邻的 Object[],没有 Node;键是 100 元素 List 时比 HashMap 快 2.8 倍;对重写了 equals 的节点按身份去重得到 3 个而不是 2 个。