标题几乎可以概括一下-我们可以创建java.util.Random
(或SecureRandom
)的一个实例,并在每次需要随机值时使用它,也可以在每次需要时创建一个新实例。想知道哪种方法是首选,为什么?让我们对上下文有一些了解:随机值是在HTTP请求处理程序内部生成的,每个请求一个,并且考虑到多线程,我正在寻找安全性和性能的最佳组合。
答案 0 :(得分:4)
要视情况而定。
创建单个实例显然更简单,并且应该是默认行为。 Random
和SecureRandom
都是线程安全的,因此可以正常工作。首先执行简单而正确的方法,然后根据预期的峰值竞争/峰值性能预算来衡量您的效果,并分析结果。
Random
如果您使用Random
并且单实例方法太慢,请考虑使用ThreadLocalRandom
。 Random
中的JavaDoc很好地建议了它的用法:
java.util.Random
的实例是线程安全的。但是,跨线程并发使用同一java.util.Random
实例可能会引起争用并因此导致性能下降。考虑在多线程设计中改为使用ThreadLocalRandom
。
它只会为每个访问它的线程创建一个实例。 Random
/ ThreadLocalRandom
实例的创建成本不是很疯狂,但是比“普通”对象的创建成本高,因此您应该避免为每个传入请求创建一个新实例。通常每个线程创建一个线程是一个不错的选择。
我想说的是,在具有池线程的现代应用程序中,几乎应始终使用ThreadLocalRandom
而不是Random
-随机性相同,但是单线程性能要好得多。
SecureRandom
但是,如果您使用的是SecureRandom
,则不能选择ThreadLocalRandom
。同样,不要猜测,测量!也许使用SecureRandom
的单个共享实例就足够了。用预期的峰值竞争进行测试,如果安全随机实例最终成为瓶颈,则只有考虑改善情况的方法。
创建SecureRandom
实例非常昂贵,因此您绝对不想为每个传入请求都创建一个实例。
根据您的应用程序,可以选择ThreadLocal<SecureRandom>
。不过,我认为这是一个过大的杀伤力,并且与Striped
类(使用X个{SecureRandom
实例被创建并随机访问以帮助防止竞争)的方案类似的方案可能是首选。
答案 1 :(得分:2)
如果您需要随机数以确保信息安全,则只能使用加密RNG(例如java.security.SecureRandom
)。对于任何加密的RNG,最简单的方法是只使用它的一个线程安全实例供整个应用程序使用(请注意,根据文档,SecureRandom
是线程安全的)。创建多个加密RNG实例通常没有任何好处,因为最终都将不得不使用高熵(“不可预测”)数据来初始化它们。
Gathering such "unpredictable" data is not trivial,并且至少对于您的应用程序,您不必担心在使用SecureRandom
时会为您执行此操作,并且其中包括setSeed
方法添加额外的数据以补充其随机性。