7071826: Avoid benign race condition in initialization of UUID
Summary: Avoids mostly benign but sometimes expensive race condition on initialization of UUID.numberGenerator which is used by UUID.randomUUID()
Reviewed-by: alanb, chegar
--- a/jdk/src/share/classes/java/util/UUID.java Fri May 11 10:09:18 2012 +0100
+++ b/jdk/src/share/classes/java/util/UUID.java Fri May 11 11:31:46 2012 -0700
@@ -90,9 +90,11 @@
/*
* The random number generator used by this class to create random
- * based UUIDs.
+ * based UUIDs. In a holder class to defer initialization until needed.
*/
- private static volatile SecureRandom numberGenerator = null;
+ private static class Holder {
+ static final SecureRandom numberGenerator = new SecureRandom();
+ }
// Constructors and Factories
@@ -137,10 +139,7 @@
* @return A randomly generated {@code UUID}
*/
public static UUID randomUUID() {
- SecureRandom ng = numberGenerator;
- if (ng == null) {
- numberGenerator = ng = new SecureRandom();
- }
+ SecureRandom ng = Holder.numberGenerator;
byte[] randomBytes = new byte[16];
ng.nextBytes(randomBytes);
@@ -255,7 +254,8 @@
* The variant number has the following meaning:
* <p><ul>
* <li>0 Reserved for NCS backward compatibility
- * <li>2 The Leach-Salz variant (used by this class)
+ * <li>2 <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF RFC 4122</a>
+ * (Leach-Salz), used by this class
* <li>6 Reserved, Microsoft Corporation backward compatibility
* <li>7 Reserved for future definition
* </ul>
@@ -265,7 +265,7 @@
public int variant() {
// This field is composed of a varying number of bits.
// 0 - - Reserved for NCS backward compatibility
- // 1 0 - The Leach-Salz variant (used by this class)
+ // 1 0 - The IETF aka Leach-Salz variant (used by this class)
// 1 1 0 Reserved, Microsoft backward compatibility
// 1 1 1 Reserved for future definition.
return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62)))
--- a/jdk/test/java/util/UUID/UUIDTest.java Fri May 11 10:09:18 2012 +0100
+++ b/jdk/test/java/util/UUID/UUIDTest.java Fri May 11 11:31:46 2012 -0700
@@ -58,6 +58,12 @@
List list = new LinkedList();
for (int i=0; i<100; i++) {
UUID u1 = UUID.randomUUID();
+ if (4 != u1.version()) {
+ throw new Exception("bad version");
+ }
+ if (2 != u1.variant()) {
+ throw new Exception("bad variant");
+ }
if (list.contains(u1))
throw new Exception("random UUID collision very unlikely");
list.add(u1);
@@ -70,10 +76,16 @@
List list = new LinkedList();
for (int i=0; i<100; i++) {
byteSource.nextBytes(someBytes);
- UUID test = UUID.nameUUIDFromBytes(someBytes);
- if (list.contains(test))
+ UUID u1 = UUID.nameUUIDFromBytes(someBytes);
+ if (3 != u1.version()) {
+ throw new Exception("bad version");
+ }
+ if (2 != u1.variant()) {
+ throw new Exception("bad variant");
+ }
+ if (list.contains(u1))
throw new Exception("byte UUID collision very unlikely");
- list.add(test);
+ list.add(u1);
}
}