【发布时间】:2017-03-29 22:29:00
【问题描述】:
这个问题是关于ThreadLocalRandom在OpenJDK 1.8.0版本中的实现。
ThreadLocalRandom 提供了一个每个线程的随机数生成器,没有 Random 带来的同步开销。最明显的实现 (IMO) 是这样的,它似乎保留了向后兼容性而没有太多复杂性:
public class ThreadLocalRandom extends Random {
private static final ThreadLocal<ThreadLocalRandom> tl =
ThreadLocal.withInitial(ThreadLocalRandom::new);
public static ThreadLocalRandom current() {
return tl.get();
}
// Random methods moved here without synchronization
// stream methods here
}
public class Random {
private ThreadLocalRandom delegate = new ThreadLocalRandom();
// methods synchronize and delegate for backward compatibility
}
然而,实际的实现却完全不同,而且相当离奇:
-
ThreadLocalRandom逐字复制Random中的一些方法,其他方法稍作修改;当然,大部分代码都可以重复使用。 -
Thread存储种子和用于初始化 `ThreadLocalRandom 的探针变量,违反封装; -
ThreadLocalRandom使用Unsafe访问Thread中的变量,我想这是因为这两个类位于不同的包中,但Thread中的状态变量必须是私有的 -Unsafe只是因为封装才需要违规; -
ThreadLocalRandom将其下一个nextGaussian存储在静态ThreadLocal中,而不是像Random那样存储在实例变量中。
总的来说,我的粗略检查似乎揭示了一个丑陋的 Random 副本,与上面的简单实现相比没有任何优势。但是标准库的作者很聪明,所以这种奇怪的方法一定有一些原因。有没有人知道为什么ThreadLocalRandom 会以这种方式实现?
【问题讨论】:
-
我还没有看到
ThreadLocalRandom的实现,但我知道parent types should not know of/depend on their subtypes(关于您更简单的替代方案) -
@VinceEmigh 好吧,两者都可以委托给
UnsynchronizedRandom。无论哪种方式,当前实现的主要问题都可以轻松避免。 -
看起来这个类是用 Java 8 重写的。JDK 1.7u79 版本只有 226 个 LOC,而 OpenJDK 8b132 version 有 1101 个 LOC。 Java 8 版本中类声明之后的代码 cmets 似乎可以解释您的一些问题。
-
Java 8 版本的内部文档中提到了
SplittableRandom,其中一些代码是重复的。 -
@dimo414 我问这个问题的真正原因是我认为这段难看的代码一定有充分的理由。如果我不认为 JDK 的作者很好,我会认为这只是糟糕的代码。关于实现细节,他们可以并且确实会在版本之间进行更改。
String.substring更改为复制 Java 7 中的子字符串,这会影响 Java 应用程序。用于随机数生成的特定算法不应该被如此详细地记录下来,也不应该被完全依赖。我认为这是 Java API 中的许多遗留错误之一。
标签: java random implementation