真实验证 BigDecimal:double 的 0.1 + 0.2 = 0.30000000000000004、new BigDecimal(0.1) 展开二进制误差;BigDecimal 是无标度整数 + scale,加减乘除的 scale 规则,除不尽抛 ArithmeticException;equals 比较 scale 所以 2.0 ≠ 2.00(HashSet 找不到);七种舍入模式对照与舍入时机。
真实验证 java.time:同一个 LocalDateTime 在四个时区是四个 Instant;夏令时让 02:30 不存在、01:30 出现两次;plusDays(1) 与 plus(24 小时) 差一小时、跳时当天 Duration 是 PT23H 而 Period 是 P1D;月末加月的结果、非法日期的异常、圣保罗的「一天开始是 01:00」。
真实验证 System.arraycopy:重叠区间安全、类型不匹配时部分复制后抛 ArrayStoreException、越界不复制;复制 100 万个 int 时 arraycopy/copyOf/clone 约 0.069 ns/元素、手写循环 0.177;-Xint 下 arraycopy 0.157 ns/元素而手写循环 7.554(慢约 48 倍)。
验证写屏障与卡表的效果和代价:老年代对象持有的年轻对象在 5 次年轻代 GC 后仍存活,引用置空后被回收;1 亿次引用存储的 ns/次:Serial 0.52、Parallel 0.519、G1 1.124、ZGC 0.756(int 存储约 0.379)。
用 jcstress 在 Apple Silicon 的 JDK 21 上跑消息传递测试(154 秒):普通读写、Opaque、Release/Acquire、volatile 四种写法都没有出现违反顺序的结果(普通与 Opaque 没有观察到不代表有保证);另一个测试里,热循环中的普通读 3 秒也看不到另一个线程的写入,而 Opaque/Acquire/volatile 读约 305 ms 后就看到了。
验证 final 字段的可见性保证:构造器里 this 逃逸时另一个线程读到 final 字段是默认值 0;反射可以修改实例 final 字段,编译期常量会被内联而读不到新值,static final 与 record 字段则抛 IllegalAccessException;用 jcstress 做数据竞争发布,final 与普通字段在这台机器上都没有读到默认值(无法区分)。
验证对象的几种发布方式:普通静态字段发布的对象,JIT 热循环里的读线程 3 秒仍看不到;volatile、AtomicReference、synchronized getter、ConcurrentHashMap 约 207 ms 后都看到了完整的对象;Thread.start、Thread.join 与类初始化器发布不需要额外同步。
用 JDK 21 的 HttpClient 对 nginx(TLS 端口 HTTP/2、明文端口 HTTP/1.1)做实测:偏好 HTTP_2 访问明文端口退回 HTTP_1_1;同一个 HttpClient 20 个请求用 1 个连接、每次新建用 20 个;50 个并发请求 HTTP/2 只用 1 个连接、HTTP/1.1 用 50 个;超时与取消的异常。
用 JDK 21 的 JSSE 做真实的 TLS 实验:协商出 TLSv1.3 与 TLS_AES_256_GCM_SHA384;自签名证书不在信任库、主机名不符、CA 签发的证书过期时分别抛出什么错误;协议版本没有交集时 protocol_version 告警;同一个 SSLContext 的会话复用;javax.net.debug 里的握手消息顺序。
真实验证 JAR:Main-Class 缺失时的报错、java -jar 不使用外部类路径;Class-Path 相对 jar 位置、manifest 每行最多 72 字节自动折行;jarsigner 签名增加 .SF 与 .EC,篡改 class 后 SHA-384 digest error;多版本 JAR 在 JDK 17、21、27 上分别选 versions/17、21、21 的实现。
在 JDK 21 上实测正则回溯:经典的 (a+)+b 等贪婪写法已经不会指数爆炸,但懒惰量词、(.*a){12}、带反向引用的模式仍然每多 4 个字符慢十几倍,n = 28 超过 2 秒;原子组、占有量词或改写模式可以解决;(a|b)* 对 4000 字符的输入栈溢出,[ab]* 不会;用自定义 CharSequence 给匹配加截止时间。
真实运行 String.format:说明符语法(宽度、补零、千分位、%x、%e、%b、%c)、舍入是 HALF_UP(%.0f 把 2.5 变成 3)、八种出错异常、Locale 对千分位与小数点(de_DE 的 1.234.567 / 1234,50)和大写(土耳其语 i → İ)的影响、参数序号 %2$s 与 %<s、Formattable。