重用java.util.Random实例与每次创建一个新实例

时间:2018-10-16 15:03:36

标签: java multithreading performance random secure-random

标题几乎可以概括一下-我们可以创建java.util.Random(或SecureRandom)的一个实例,并在每次需要随机值时使用它,也可以在每次需要时创建一个新实例。想知道哪种方法是首选,为什么?让我们对上下文有一些了解:随机值是在HTTP请求处理程序内部生成的,每个请求一个,并且考虑到多线程,我正在寻找安全性和性能的最佳组合。

2 个答案:

答案 0 :(得分:4)

要视情况而定。

创建单个实例显然更简单,并且应该是默认行为。 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实例被创建并随机访问以帮助防止竞争)的方案类似的方案可能是首选。

答案 1 :(得分:2)

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

Gathering such "unpredictable" data is not trivial,并且至少对于您的应用程序,您不必担心在使用SecureRandom时会为您执行此操作,并且其中包括setSeed方法添加额外的数据以补充其随机性。