【问题标题】:Reusing java.util.Random instance vs creating a new instance every time重用 java.util.Random 实例与每次都创建一个新实例
【发布时间】:2018-10-16 15:03:36
【问题描述】:

标题几乎概括了它——我们可以创建一个java.util.Random(或SecureRandom)的实例,并在每次需要随机值时使用它,或者我们可以在每次需要时创建一个新实例。想知道哪一种是首选方式,为什么?

为了说明上下文:随机值是在 HTTP 请求处理程序中生成的,每个请求一个,考虑到多线程,我正在寻找安全性和性能的最佳组合。

【问题讨论】:

  • 没有所谓的“随机数”。每当您看到“随机”这个词时,都会认为“不可预测”。一个数字,就其本身而言,是不可预测的。这甚至意味着什么? java.util.Random 实例不会为您提供孤立的随机数:它会为您提供不可预测的 sequence 数字。

标签: java multithreading performance random secure-random


【解决方案1】:

视情况而定。

创建单个实例显然更简单,应该是默认行为。 RandomSecureRandom 都是线程安全的,因此可以正常工作。首先做简单而正确的事情,然后根据预期的峰值竞争/峰值性能预算衡量您的性能,并分析结果。

Random

如果您使用Random 并且单实例方法太慢,请尽可能考虑使用ThreadLocalRandomRandom 中的 JavaDoc 很好地建议了它的用法:

java.util.Random 的实例是线程安全的。但是,跨线程并发使用相同的java.util.Random 实例可能会遇到争用,从而导致性能下降。考虑在多线程设计中改用ThreadLocalRandom

它只会为每个访问它的线程创建一个实例。 Random / ThreadLocalRandom 实例的创建成本并不高,但它比创建“普通”对象要高,因此您应该避免为每个传入请求创建一个新实例。每个线程创建一个通常是一个不错的最佳位置。

我想说的是,在具有池化线程的现代应用程序中,您几乎应该总是使用ThreadLocalRandom 而不是Random - 随机性相同,但单线程性能要好得多。

SecureRandom

但是,如果您使用的是SecureRandom,则不能选择ThreadLocalRandom。再次,不要猜测,测量!也许使用SecureRandom 的单个共享实例就足够了。使用您预期的峰值竞争进行测试,如果安全随机实例成为瓶颈,然后再考虑改善这种情况的方法。

创建SecureRandom 实例的成本非常高,因此您绝对不想为每个传入的请求创建一个。

根据您的应用程序,ThreadLocal<SecureRandom> 可能是一个选项。不过,我认为这有点矫枉过正,可能首选类似于 Striped 类的方案(随机创建和访问 X 个 SecureRandom 实例以帮助防止争用)。

【讨论】:

    【解决方案2】:

    如果您需要随机数来确保信息安全,则只有加密 RNG(例如 java.security.SecureRandom)可以。对于任何加密 RNG,最简单的方法是只使用它的一个线程安全实例供整个应用程序使用(请注意,根据文档,SecureRandom 是线程安全的);创建加密 RNG 的多个实例通常没有任何好处,因为它们最终都必须使用高熵(“不可预测”)数据进行初始化。

    Gathering such "unpredictable" data is not trivial,至少对于您的应用程序,当您使用 SecureRandom 时,您不必担心这一点,它在很大程度上为您完成了这项工作,并包括一个 setSeed 方法,您可以使用它来添加额外的数据来补充它随机性。

    【讨论】:

    • 感谢您的回答,能否请您详细说明最后一部分?
    猜你喜欢
    • 1970-01-01
    • 2022-01-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-11
    • 2012-10-07
    • 2018-06-25
    • 1970-01-01
    相关资源
    最近更新 更多