提交 f3c46a62 编写于 作者: M mduigou

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
上级 22f07d2e
...@@ -90,9 +90,11 @@ public final class UUID implements java.io.Serializable, Comparable<UUID> { ...@@ -90,9 +90,11 @@ public final class UUID implements java.io.Serializable, Comparable<UUID> {
/* /*
* The random number generator used by this class to create random * 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 // Constructors and Factories
...@@ -137,10 +139,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID> { ...@@ -137,10 +139,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID> {
* @return A randomly generated {@code UUID} * @return A randomly generated {@code UUID}
*/ */
public static UUID randomUUID() { public static UUID randomUUID() {
SecureRandom ng = numberGenerator; SecureRandom ng = Holder.numberGenerator;
if (ng == null) {
numberGenerator = ng = new SecureRandom();
}
byte[] randomBytes = new byte[16]; byte[] randomBytes = new byte[16];
ng.nextBytes(randomBytes); ng.nextBytes(randomBytes);
...@@ -255,7 +254,8 @@ public final class UUID implements java.io.Serializable, Comparable<UUID> { ...@@ -255,7 +254,8 @@ public final class UUID implements java.io.Serializable, Comparable<UUID> {
* The variant number has the following meaning: * The variant number has the following meaning:
* <p><ul> * <p><ul>
* <li>0 Reserved for NCS backward compatibility * <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&nbsp;RFC&nbsp;4122</a>
* (Leach-Salz), used by this class
* <li>6 Reserved, Microsoft Corporation backward compatibility * <li>6 Reserved, Microsoft Corporation backward compatibility
* <li>7 Reserved for future definition * <li>7 Reserved for future definition
* </ul> * </ul>
...@@ -265,7 +265,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID> { ...@@ -265,7 +265,7 @@ public final class UUID implements java.io.Serializable, Comparable<UUID> {
public int variant() { public int variant() {
// This field is composed of a varying number of bits. // This field is composed of a varying number of bits.
// 0 - - Reserved for NCS backward compatibility // 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 0 Reserved, Microsoft backward compatibility
// 1 1 1 Reserved for future definition. // 1 1 1 Reserved for future definition.
return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62)))
......
...@@ -58,6 +58,12 @@ public class UUIDTest { ...@@ -58,6 +58,12 @@ public class UUIDTest {
List list = new LinkedList(); List list = new LinkedList();
for (int i=0; i<100; i++) { for (int i=0; i<100; i++) {
UUID u1 = UUID.randomUUID(); 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)) if (list.contains(u1))
throw new Exception("random UUID collision very unlikely"); throw new Exception("random UUID collision very unlikely");
list.add(u1); list.add(u1);
...@@ -70,10 +76,16 @@ public class UUIDTest { ...@@ -70,10 +76,16 @@ public class UUIDTest {
List list = new LinkedList(); List list = new LinkedList();
for (int i=0; i<100; i++) { for (int i=0; i<100; i++) {
byteSource.nextBytes(someBytes); byteSource.nextBytes(someBytes);
UUID test = UUID.nameUUIDFromBytes(someBytes); UUID u1 = UUID.nameUUIDFromBytes(someBytes);
if (list.contains(test)) 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"); throw new Exception("byte UUID collision very unlikely");
list.add(test); list.add(u1);
} }
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册