我有两种代码选择:
选项 1
int myFunc() {
return new Random().nextInt();
}
或者:
选项 2
private static final Random random = new Random();
int myFunc() {
return random.nextInt();
}
我知道选项 2
更符合习惯。我想知道选项 1
的有效性。
在选项 1
中,我只会使用给定种子生成的第一个数字。在 选项 2
中,我选择一个种子并使用该种子生成 n
个数字。 IIUC 对随机性的保证就在这个用例上。
因此,我的问题是,如果我多次调用选项 1
,是否可以保证输出分布的均匀性?
最佳答案
快速代码:
// For occasional tasks that just need an average quality random number
ExecutorService threadPool = Executors.newCachedThreadPool();
threadPool.execute( () -> {
ThreadLocalRandom.current().nextInt(); // Fast and unique!
} );
// For SecureRandom, high quality random number
final Random r = new SecureRandom();
ExecutorService threadPool = Executors.newCachedThreadPool();
threadPool.execute( () -> {
r.nextInt(); // sun.security.provider.NativePRNG uses singleton. Can't dodge contention.
} );
// Apache Common Math - Mersenne Twister - decent and non-singleton
int cpu = Runtime.getRuntime().availableProcessors();
ExecutorService executor = Executors.newFixedThreadPool( cpu );
Map<Thread, RandomGenerator> random = new WeakHashMap<>( cpu, 1.0f );
executor.execute( ()-> {
RandomGenerator r;
synchronized ( random ) { // Get or create generator.
r = random.get( Thread.currentThread() );
if ( r == null ) random.put( Thread.currentThread(), r = new MersenneTwister() );
}
r.nextInt( 1000 );
} );
解释:
- 相同种子的两个
随机
将产生相同的数字。- 因此我们将重点关注是否可以保证不同的种子。
理论上,每个线程中的
new Random()
并不能保证不同的seed。- 新随机由 nanoTime 和一个“唯一”数字作为种子。
- 不能保证该数字是唯一的,因为它的计算是不同步的。
- 至于 nanoTime,它保证“至少与 currentTimeMillis 一样好”
- currentTimeMillis 不保证任何东西,可以是 pretty coarse。
- 在现实生活中,这两个时间仅在 old linux systems and Win 98 上相同。
在实践中,每个线程中的
new Random()
基本上总是得到不同的种子。- 创建线程是昂贵的。我的每 50,000 纳秒创建 1 个。那是 not slow 。
- 50µs 远高于 nanoTime 最高达 a few ten ns 的常见粒度。
- 唯一数计算(1.2)也很快,所以得到相同的数字是非常罕见的。
- 使用 Executors 创建一个 thread pool 以避免繁重的新线程开销。
zapl suggested
ThreadLocalRandom.current().nextInt()
。好主意。- 它不会创建新的
Random
,但它也是一个 linear congruential generator 。 - 它为每个调用线程生成一个新的随机数作为该线程的种子。
- 它被构建为在多线程中非常快。 (见下面的注释。)
- 它由
SecureRandom
静态播种,产生质量更好的随机数。
- 它不会创建新的
“均匀分布”只是 randomness tests 的一小部分。
Random
是 somewhat uniform ,它的结果可以是 predicted 给定两个值。-
SecureRandom
保证 this won't happens 。 (即加密强度高) - 如果您在每个线程中创建一个新的
SecureRandom
,就没有种子冲突的风险。 - 但目前它的来源无论如何都是single thread,没有并行生成。
- 对于支持多线程的良好 RNG,找到 external help,例如 Apache Common 的 MT。
Note: Implementation details deduced from Java 8 source code. Future Java version may change; for example,
ThreadLocalRandom
is usingsun.misc.Unsafe
to store the seeds, which may be removed in Java 9 forcing ThreadLocalRandom to find a new way to work without contention.
关于java - 随机数的分布,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38242833/