Rei*_*ica 10 java random implementation
这个问题关注ThreadLocalRandomOpenJDK版本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
}
Run Code Online (Sandbox Code Playgroud)
但是,实际的实现是完全不同的,非常奇怪:
ThreadLocalRandomRandom逐字复制一些方法,稍作修改; 当然,大部分代码都可以重用.Thread 存储种子和用于初始化`ThreadLocalRandom的探测变量,违反封装;ThreadLocalRandom使用Unsafe访问的变量Thread,我想是因为这两个类在不同的包却状态变量必须是私有的Thread- Unsafe是因为封装违反唯一必要的;ThreadLocalRandom将其下nextGaussian一个存储在静态ThreadLocal而不是实例变量Random中.总的来说,我粗略的检查似乎揭示了一个丑陋的副本,Random与上面的简单实现没有任何优势.但是标准库的作者很聪明,所以这种奇怪的方法必须有一些原因.有没有人知道为什么这样ThreadLocalRandom实现?
dim*_*414 10
关键问题是许多代码都是遗留的,无法(轻松)更改 - Random通过同步其所有方法而被设计为"线程安全".这样Random可以在多个线程中使用,但是这是一个严重的瓶颈,因为没有两个线程可以同时检索随机数据.一个简单的解决方案是构造一个ThreadLocal<Random>对象,从而避免锁争用,但这仍然不理想.即使在无争议的情况下,方法仍然存在一些开销synchronized,并且当它们基本上完成同样的工作时,构造n个 Random实例是浪费的.
因此,在高级别ThreadLocalRandom存在作为性能优化,因此它的实现将是"奇怪的",因为JDK开发人员已经花时间来优化它.
JDK中有许多类,乍一看是"丑陋的".但请记住,JDK作者正在解决与您不同的问题.他们编写的代码将以数千甚至数百万的开发人员以无数方式使用.他们必须定期权衡最佳实践以提高效率,因为他们编写的代码非常关键.
有效的Java:第55项也解决了这个问题 - 关键点是优化应该由专家作为最后的手段来完成.JDK开发人员就是那些专家.
针对您的具体问题:
ThreadLocalRandomRandom逐字复制一些方法,稍作修改; 当然,大部分代码都可以重用.
不幸的是,没有,因为方法Random是synchronized.如果他们被调用ThreadLocalRandom会引起Random锁定争用的麻烦.TLR 需要覆盖每个方法,以便synchronized从方法中删除关键字.
Thread存储种子和用于初始化ThreadLocalRandom违反封装的探测变量;
首先,它实际上不是"违反封装",因为该字段仍然是封装私有的.它是由用户封装的,这是目标.我不会对此过于笼罩,因为这里的决定是为了提高性能.有时性能是以正常的良好设计为代价的.在实践中,这种"违规"是无法察觉的.行为简单地封装在两个类中而不是单个类中.
将种子置于内部Thread允许ThreadLocalRandom完全无状态(除了initialized字段之外,这在很大程度上是不相关的),因此在整个应用程序中只需要存在单个实例.
ThreadLocalRandom使用Unsafe访问的变量Thread,我想是因为这两个类在不同的包却状态变量必须是私有的Thread-Unsafe是因为封装违反唯一必要的;
许多JDK类都使用Unsafe.这是一种工具,而不是罪恶.再一次,我不会对这个事实太过强调.该课程被要求Unsafe阻止非专业开发人员滥用它.我们相信/希望JDK作者足够聪明,知道什么时候可以安全使用.
ThreadLocalRandom将其下nextGaussian一个存储在静态ThreadLocal而不是实例变量Random中.
因为只有一个实例,ThreadLocalRandom所以不需要将它作为实例变量.我想你可以选择说它不需要它static,但那时候你只是在讨论风格.至少使它static更清楚地让班级基本上无国籍.正如所提到的文件中,这个字段是不是真的有必要,但能保证类似的行为Random.