编程语言
首页 > 编程语言> > 为什么ThreadLocalRandom的实现如此奇怪?| Java Debug 笔记

为什么ThreadLocalRandom的实现如此奇怪?| Java Debug 笔记

作者:互联网

本文正在参加「Java主题月 - Java Debug笔记活动」,详情查看活动链接

提问:为什么ThreadLocalRandom的实现如此奇怪?

这个问题涉及在开放日DK版本1.8.0的实施。ThreadLocalRandom

ThreadLocalRandom提供一个每线程随机数生成器,而无需随机强加的同步开销。最明显的实现 (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用于访问变量,我想这是因为两个类是在不同的包,但状态变量必须是私人的 - 只是因为封装违规:UnsafeThreadThreadUnsafe

ThreadLocalRandom存储其下一个静态,而不是在实例变量中存储。nextGaussianThreadLocalRandom 总的来说,我粗略的检查似乎揭示了一个丑陋的副本,没有优势,而不是简单的实现以上。但是标准图书馆的作者很聪明,所以这种奇怪的方法一定有一些原因。是否有人对为何以这种方式实施有任何见解?RandomThreadLocalRandom

高分回答:

键问题是很多代码是遗留下来的,不能(容易)更改 - Random被设计为"线程安全"通过同步其所有方法。这工作,在这种情况下,可以跨多个线程使用,但它是一个严重的瓶颈,因为没有两个线程可以同时检索随机数据。一个简单的解决方案是构建一个对象,从而避免锁的争夺,但这仍然不理想。即使没有争议,方法仍有一些开销,当它们基本上都在做同样的工作时,构建n实例也是浪费。

RandomThreadLocal<Random>synchronizedRandom
复制代码

因此,在高层存在作为性能优化,因此,它的实现将是"荒唐的",因为JDK开发人员已经投入了时间来优化它。ThreadLocalRandom

JDK 中有许多类,乍一看是"丑陋的"。但是请记住,JDK 作者正在解决与您不同的问题。他们编写的代码将被成千上万的开发人员以无数的方式使用。他们必须定期权衡最佳实践以获得效率,因为他们编写的代码对任务至关重要。

Effective Java:第 55 项还解决了此问题 - 关键是专家应作为最后手段进行优化。JDK开发人员是这些专家。

具体问题:

ThreadLocalRandom逐字复制一些方法,其他方法稍作修改;当然,这个代码的大部分可以重复使用。Random

不幸的是没有,因为方法是。如果他们被援引,将拉在锁争夺麻烦。TLR需要覆盖所有方法,以便从方法中删除关键字。RandomsynchronizedThreadLocalRandomRandomsynchronized

Thread存储用于初始化的种子和探针变量,违反封装:ThreadLocalRandom

首先,它实际上不是"违反封装",因为字段仍然是包私人的。它从用户那里封装,这是目标。我不会太挂上这个, 因为在这里的决定是为了提高性能。有时性能是以正常的良好设计为代价的。实际上,这种"违规行为"是无法察觉的。该行为只是封装在两个类中,而不是一个单一类。

将种子放入内部允许完全无状态(除了字段,这在很大程度上无关紧要),因此在整个应用程序中只需要存在一个实例。ThreadThreadLocalRandominitialized

ThreadLocalRandom用于访问变量,我想这是因为两个类是在不同的包,但状态变量必须是私人的 - 只是因为封装违规:UnsafeThreadThreadUnsafe

许多jdk类使用。这是工具,不是罪。再说一遍, 我就是不会对这个事实太紧张。该课程旨在阻止非专业开发人员滥用它。我们相信/希望JDK的作者足够聪明,知道什么时候可以安全使用。UnsafeUnsafe

ThreadLocalRandom存储其下一个静态,而不是在实例变量中存储。nextGaussianThreadLocalRandom

由于只有一个实例,因此无需此实例变量。我想你也可以证明, 也没有必要成为一个, 但在这一点上, 你只是辩论风格。至少使它更清楚地离开类基本上无状态。如文件所述,此字段并不真正必要,但可确保与。ThreadLocalRandomstaticstaticRandom

文章翻译自 stackoverflow.com/questions/4…

真心感谢帅逼靓女们能看到这里,如果这个文章写得还不错,觉得有点东西的话

求点赞???? 求关注❤️ 求分享???? 对8块腹肌的我来说真的 非常有用!!!

如果本篇博客有任何错误,请批评指教,不胜感激 !❤️❤️❤️❤️

标签:封装,ThreadLocalRandom,JDK,Random,线程,Debug,Java
来源: https://blog.51cto.com/u_10182395/2787130