5

Given the following code snippet, which generates a UUID.randomUUID(), I get the following performance results (in milliseconds):

public static void main(String[] args) { long tmp = System.currentTimeMillis(); UUID.randomUUID(); tmp = printDiff(tmp); UUID.randomUUID(); tmp = printDiff(tmp); UUID.randomUUID(); tmp = printDiff(tmp); UUID.randomUUID(); tmp = printDiff(tmp); } private static long printDiff(final long previousTimestamp) { long tmp = System.currentTimeMillis(); System.out.printf("%s%n", tmp - previousTimestamp); return tmp; } 

Results:

971 6 0 0 

JDK: 1.8 OS: Windows 7

Why does only the initial call take so long? (Nearly 1 second!)

2
  • @4castle its not, there are only 4 invocations here, there's no JIT Commented Jan 23, 2017 at 0:44
  • 1
    Initialization of SecureRandom can be really slow on Windows due to network interface scanning etc. See this question for details. Commented Jan 23, 2017 at 7:22

3 Answers 3

7

it's the initialization of the SecureRandom that is done once:

//from the source code of randomUUID private static class Holder { static final SecureRandom numberGenerator = new SecureRandom(); } 

But that's not all here. Those zeroes should really jump into your face. So the operation took 0 milliseconds; does it mean they took less? like a few nano-seconds or you are doing something wrong?

There's a proper tool to measure this things, called jmh.

@BenchmarkMode({ Mode.AverageTime, Mode.SingleShotTime }) @OutputTimeUnit(TimeUnit.MILLISECONDS) @Warmup(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 2, time = 2, timeUnit = TimeUnit.SECONDS) @State(Scope.Benchmark) public class UUIDRandom { public static void main(String[] args) throws RunnerException { Options opt = new OptionsBuilder().include(UUIDRandom.class.getSimpleName()).build(); new Runner(opt).run(); } @Benchmark @Fork(1) public UUID random() { return UUID.randomUUID(); } } 

and the output says:

Benchmark Mode Cnt Score Error Units UUIDRandom.random avgt 2 0.002 ms/op UUIDRandom.random ss 2 0.094 ms/op 

Indeed single-shot time is far worse then the average.

Sign up to request clarification or add additional context in comments.

Comments

0

The first time UUID.randomUUID() is called, it has to initialize some internal objects which it uses in all subsequent calls as well.

The source code for UUID.randomUUID is:

public static UUID randomUUID() { SecureRandom ng = Holder.numberGenerator; byte[] randomBytes = new byte[16]; ng.nextBytes(randomBytes); randomBytes[6] &= 0x0f; /* clear version */ randomBytes[6] |= 0x40; /* set to version 4 */ randomBytes[8] &= 0x3f; /* clear variant */ randomBytes[8] |= 0x80; /* set to IETF variant */ return new UUID(randomBytes); } 

Here, Holder.numberGenerator is a global variable which, on first use, has to be initialized:

private static class Holder { static final SecureRandom numberGenerator = new SecureRandom(); } 

Comments

0

Based on the Java 8 codes, it looks like creating a SecureRandom object is expensive.That's why they defer initialization until needed (aka lazy initialization) and reuse it in subsequent invocation.

/* * The random number generator used by this class to create random * based UUIDs. In a holder class to defer initialization until needed. */ private static class Holder { static final SecureRandom numberGenerator = new SecureRandom(); } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.