知其然,知其所以然
Java 内部原理 2026-06-25

try-with-resources 没有主异常时:close() 的异常真实直接抛出,不是 suppressed

真实验证 try 主体正常执行完、只有 close() 抛异常的场景:调用方真实 catch 到的就是 close() 直接抛出的那个异常本身,getSuppressed() 真实是空数组,不是被包进了谁的 suppressed 里——因为这时候没有更值得优先报告的主异常,close() 的异常本身就真实升级成了主异常。对照 try 主体也抛异常的场景,close() 的异常这才真实变成 suppressed。第三组验证两个资源都在 close() 抛异常时,真实是最后关闭的那个变成主异常。

Java 异常 try-with-resources 动画演示
Java 内部原理 2026-06-24

parallelStream() 真实用了几个线程:真实捕获到 main 线程也参与了计算

真实捕获 parallelStream 处理 1 万个元素时真实用到的所有线程名,结果是 10 个线程(9 个 ForkJoinPool.commonPool 工作线程 + main 线程本身),真实验证 main 线程也真实参与了计算,不是完全外包给线程池;对照普通 stream() 真实只用了 main 一个线程。真实计时一个 2000 万元素的平方和任务,预热后并行版本真实比串行快了约 4.48 倍。

Java parallelStream 并发 动画演示
Java 内部原理 2026-06-23

Stream 的惰性:真实验证 count() 有时候连中间操作都真实不会执行

真实验证只声明 map 不调用终端操作,map 里的打印语句真实一行都不会执行;调用 count() 之后真实检查,发现依然没有任何打印——不是因为惰性求值按元素延迟执行,而是 JDK 真实做了更彻底的优化:count() 在能确定元素个数不会变的场景下,直接跳过整个 map 逻辑。真实验证 findFirst() 的短路特性:处理到第 4 个元素满足条件就真实停止,不会处理完全部 10 个。

Java Stream 惰性求值 动画演示
Java 内部原理 2026-06-22

static synchronized 锁的是 Class 对象:真实验证它和实例锁真的互不阻塞

两个不同实例并发调用各自的 synchronized 实例方法,真实总耗时约 503ms,证明真实并行、互不阻塞;换成两次并发调用同一个 static synchronized 方法,哪怕通过不同实例发起调用,真实总耗时约 1008ms,证明真实互相阻塞,共享同一把类级别的锁;第三组真实验证:一个线程持有某个实例的对象锁忙着的时候,另一个线程调用这个类的 static synchronized 方法真实完全不受影响。

Java synchronized 并发 动画演示
Java 内部原理 2026-06-21

synchronized 方法和 synchronized(this) 块:真实验证锁的是同一把锁

一个线程调用 synchronized 方法(锁住 this)期间真实 sleep 500ms,另一个线程紧接着调用 synchronized(this) 块版本的方法,真实测出等待了约 808ms(500ms 排队 + 300ms 自己执行),证明两者真实抢的是同一把对象锁;反过来用 synchronized 方法去等一个 synchronized(this) 块持有的锁,真实测出同样约 805ms 的等待,验证 synchronized 方法本质上就是对整个方法体包一层 synchronized(this)。

Java synchronized 并发 动画演示
Java 内部原理 2026-06-20

Fork/Join 真实分给了几个线程:真实验证 4 个工作线程真的都参与了计算

用 RecursiveTask 实现一个分治求和,限定 ForkJoinPool 只有 4 个工作线程,真实跑 2000 万个元素的数组求和:真实记录到 4 个不同的 ForkJoinPool 工作线程都参与了计算,和线程池的并行度设置精确对应;真实结果和单线程顺序求和完全一致;但真实计时发现,对这种每个元素只做一次加法的极轻量任务,Fork/Join 版本反而比顺序循环慢了近一倍——任务切分和线程调度的真实开销,在计算量太小时会超过并行带来的收益。

Java Fork/Join 并发 动画演示
Java 内部原理 2026-06-19

BigDecimal 精度陷阱:真实验证 new BigDecimal(0.1) 会原样继承 double 的不精确

真实验证 0.1 + 0.2 用 double 计算真实等于 0.30000000000000004,不等于 0.3;打印 0.1 在 double 里真实存储的完整精度,发现它本来就不是精确的 0.1;真实验证 new BigDecimal(0.1) 会原样把这份不精确继承过来,而 BigDecimal.valueOf(0.1) 和 new BigDecimal 字符串版本真实都得到精确的 0.1。额外真实验证 BigDecimal 的 equals 对小数位数敏感,compareTo 才是真正的数值比较。

Java BigDecimal 浮点数 动画演示
Java 内部原理 2026-06-18

可变参数遇上重载:真实验证参数个数对得上时,编译器真实优先选固定版本

同时定义 pick(int a, int b) 和 pick(int... nums),真实调用 pick(1, 2):编译器真实选中固定两参数版本,不是可变参数版本;调用 pick(1, 2, 3)、pick(1)、pick() 这些参数个数对不上固定版本的场景,才真实退而选中可变参数版本。真实验证类型匹配上也遵循同样优先级:pick2(String) 和 pick2(Object...) 同时存在时,pick2(hello) 真实选中固定 String 版本。

Java 可变参数 重载 动画演示
Java 内部原理 2026-06-17

Optional 本身可以是 null:真实验证这个类型没能真正杜绝 NPE

真实验证空 Optional 调用 get() 真实抛出 NoSuchElementException;更关键的是,写一个返回类型是 Optional<String> 但内部直接 return null 的方法,真实验证编译器完全不会阻止这一行,调用方拿到的返回值真实是 null,对它调用 isPresent() 真实抛出 NullPointerException——Optional 类型本身没有任何语言层面的机制阻止它自己变成 null。对照 orElse/ifPresentOrElse 等正确用法真实不需要显式判空。

Java Optional NPE 动画演示
Java 内部原理 2026-06-16

thenApply 真实可能在调用线程执行,不一定是线程池:真实测出两种结果

真实验证 supplyAsync 默认在 ForkJoinPool.commonPool 的工作线程执行,和 main 线程真实不同;但紧跟着的 thenApply(不带 Async 后缀)在 supplyAsync 几乎瞬间完成的情况下,真实在 main 线程执行,不是线程池;把 supplyAsync 真实故意拖慢到 200ms,同一个 thenApply 这次真实变成在线程池工作线程执行。真实证明:不带 Async 后缀的回调,由谁执行取决于回调附加时前一步是否已经完成,不是固定跑在线程池里。

Java CompletableFuture 并发 动画演示
Java 内部原理 2026-06-15

Record 类真实反编译:equals/hashCode/toString 是一条 invokedynamic,不是手写代码

定义 record Point(int x, int y),真实验证 equals() 按字段值比较、hashCode() 相应相等、toString() 自动生成 Point[x=3, y=4] 格式、访问器方法名就是字段名本身;真实验证紧凑构造函数里的校验逻辑会执行。用 javap 反编译发现 equals/hashCode/toString 在字节码里各自只是一条 invokedynamic 指令,真正的比较逻辑由 JDK 内部的 ObjectMethods 引导方法在运行时生成,不是编译器手写进类文件里的。

Java Record Java 16+ 动画演示
Java 内部原理 2026-06-14

Comparator 违反契约:真实触发 JDK 自带的 Comparison method violates its general contract

写一个看起来合理、实际违反传递性的比较器(差值小于 2 就判定相等),先用三个数真实证明 compare(10,11)=0、compare(11,12)=0,但 compare(10,12)=-2,传递性真实被破坏;换成完全随机的比较器,数组长度 64,真实在第 6 次尝试时触发 IllegalArgumentException;对照数组长度 20(小于 TimSort 的 MIN_MERGE=32 阈值),跑 2000 次同样的随机比较器,真实一次都没有触发。

Java Comparator TimSort 动画演示
京ICP备2026067502号-1京公网安备11010502063487号