JDK17及以上ThreadLocalRandom为何直接调用super.nextInt?
首先要澄清一个误解:ThreadLocalRandom并没有失去线程本地特性,它的核心优势——线程独有的随机数种子管理逻辑依然存在,只是将随机数生成的算法逻辑统一到了父类Random中,这么做的主要原因有以下几点:
代码复用与维护成本降低
JDK8中ThreadLocalRandom自行实现了一套完整的nextXXX系列方法,和父类Random的实现存在大量重复代码。JDK17+将通用的随机数生成逻辑(比如边界处理、非2的幂次情况下的拒绝采样逻辑)统一到了Random类中,ThreadLocalRandom只需要专注于自己的核心职责——线程本地种子的生成与更新(比如nextSeed()方法依然是ThreadLocalRandom独有的线程本地实现)。这样后续对随机数算法的优化、Bug修复只需要在父类中进行,不用同步修改子类,大幅降低了维护成本。父类Random的适配进化
JDK17+对Random类做了适配,其nextXXX方法的底层实现依赖于next(int bits)方法,而ThreadLocalRandom重写了这个next(int bits)方法,依然使用线程本地的种子来生成随机位序列。所以表面上ThreadLocalRandom调用super.nextInt(bound),实际执行时还是会走到自己的线程本地种子逻辑,完全保留了原有的线程安全、无锁竞争的特性,和JDK8的实现性能、效果一致。API兼容性保障
这种实现方式完全兼容原有代码,开发者不需要修改任何调用ThreadLocalRandom的代码,就能享受到内部实现优化带来的好处,同时保持了API的稳定性。
内容的提问来源于stack exchange,提问作者NOSAE

