我决定问Java编译器。简短的回答是,是的,重用SecureRandom
对象有一些性能优势,但不是更好或更糟的是实际随机性。这纯粹是一个调优问题。不是安全问题。
但是请注意,JIT 需要一段时间才能启动,这样您才能看到好处。要点是,对于重度/频繁使用,绝对要重复使用该对象。对于不经常使用的情况,您最好每次都使用一个新对象。
结果
warm up
-----------------------------
default seed - re-use - 1807 ms
explicit seed - re-use - 835 ms
constant seed - new every time - 1044 ms
default seed - new every time - 1621 ms
-----------------------------
interation 0
-----------------------------
default seed - re-use - 412 ms
explicit seed - re-use - 418 ms
constant seed - new every time - 955 ms
default seed - new every time - 1676 ms
-----------------------------
interation 1
-----------------------------
default seed - re-use - 389 ms
explicit seed - re-use - 369 ms
constant seed - new every time - 893 ms
default seed - new every time - 1498 ms
来源
package foo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.security.SecureRandom;
import java.util.HashSet;
import java.util.Set;
import org.junit.BeforeClass;
import org.junit.Test;
public class SecureRandomTest {
static long elapsedMillis( long startNs ) {
long now = System.nanoTime();
return (now - startNs) / 1_000_000;
}
final static long seed = 123456789123456L;
final static int nIter = 1000000;
public static void main(String[] args) {
warmup();
SecureRandomTest test = new SecureRandomTest();
for ( int ix = 0; ix < 5; ++ix ) {
test.run(ix);
}
}
void run(int ix) {
System.out.printf( "interation %d\n-----------------------------\n", ix);
secure_random_default_seed_reuse();
secure_random_constant_seed_reuse();
secure_random_constant_seed();
secure_random_default_seed();
System.out.println("-----------------------------");
}
/* Warm up JVM/JIT */
@BeforeClass
public static void warmup() {
new SecureRandomTest().run(-1);
}
@Test
public void secure_random_constant_seed() {
long started = System.nanoTime();
int nDupes = 0, ix = 0;
Set<Long> generated = new HashSet<>(nIter);
for ( /**/; ix < nIter; ++ix) {
SecureRandom rand = new SecureRandom();
rand.setSeed(seed);
long xRand = rand.nextLong();
if ( !generated.add(xRand) ) {
++nDupes;
}
}
assertEquals( "Unexpected # of dupes " + nDupes + ", ix == " + ix, nIter-1, nDupes );
System.out.printf( "constant seed - new every time - %d ms\n", elapsedMillis(started) );
}
@Test
public void secure_random_constant_seed_reuse() {
long started = System.nanoTime();
int nDupes = 0, ix = 0;
SecureRandom rand = new SecureRandom();
rand.setSeed(seed);
Set<Long> generated = new HashSet<>(nIter);
for ( /**/; ix < nIter; ++ix) {
long xRand = rand.nextLong();
if ( !generated.add(xRand) ) {
++nDupes;
}
}
assertTrue( "Unexpected # of dupes " + nDupes + ", ix == " + ix, 0 == nDupes );
System.out.printf( "explicit seed - re-use - %d ms\n", elapsedMillis(started) );
}
@Test
public void secure_random_default_seed() {
long started = System.nanoTime();
int nDupes = 0, ix = 0;
Set<Long> generated = new HashSet<>(nIter);
for ( /**/; ix < nIter; ++ix) {
long xRand = new SecureRandom().nextLong();
if ( !generated.add(xRand) ) {
++nDupes;
}
}
assertTrue( "Unexpected # of dupes " + nDupes + ", ix == " + ix, 0 == nDupes );
System.out.printf( "default seed - new every time - %d ms\n", elapsedMillis(started) );
}
@Test
public void secure_random_default_seed_reuse() {
long started = System.nanoTime();
int nDupes = 0, ix = 0;
SecureRandom rand = new SecureRandom();
Set<Long> generated = new HashSet<>(nIter);
for ( /**/; ix < nIter; ++ix) {
long xRand = rand.nextLong();
if ( !generated.add(xRand) ) {
++nDupes;
}
}
assertTrue( "Unexpected # of dupes " + nDupes + ", ix == " + ix, 0 == nDupes );
System.out.printf( "default seed - re-use - %d ms\n", elapsedMillis(started) );
}
}