Learning Java source code: UUID

I. Introduction

As developers, you should be familiar with UUID. Java also provides relevant classes and generation methods for business use. Here we are going to have an in-depth understanding of the process of UUID generation.

Second, what is UUID

2.1 concept

According to the description of Baidu Encyclopedia:

UUID is the abbreviation of universal unique identifier. It is a standard for software construction. It is also a part of the open software foundation in the field of distributed computing environment. Its purpose is to make all elements in the distributed system have unique identification information without specifying the identification information through the central control end. In this way, everyone can create UUIDs that do not conflict with others.

2.2 UUID instance

In reality, the most widely used UUID is Microsoft's globally unique identifier (GUID), while other important applications include Linux ext2/ext3 file system, LUKS encrypted partition, GNOME, KDE, Mac OS X, etc.

There happens to be a mac computer at hand. We can view the hardware uuid by clicking the apple Icon -- > about this computer -- > system report -- > Hardware -- > Hardware uuid in the upper left corner of the computer.

2.3 UUID composition

UUID consists of the following parts:

(1) The first part of UUID is related to time. If you generate a UUID after a few seconds, the first part is different and the rest are the same.

(2) Clock sequence.

(3) The globally unique IEEE machine identification number. If there is a network card, it is obtained from the MAC address of the network card. If there is no network card, it is obtained in other ways.

The generated result string will be long, which is a defect of UUID. The most commonly used standard for UUID is the Microsoft guid (global unique identifiers). In ColdFusion, you can use the CreateUUID() function to simply generate UUIDs in the format of XXXXXXXX - XXXX - xxxxxxxxxxxxxxxxxx (8-4-4-16), where each x is a hexadecimal number in the range of 0-9 or a-f. The standard UUID format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx (8-4-4-4-12). You can download CreateGUID() UDF from cflib for conversion.

III. UUID class in Java

3.1 java.util.UUID

java. The util package provides a UUID class, which contains methods to generate UUIDs for developers to call. Some comments are also made in the document, from which we can also learn more detailed information about UUID (the following are some key information intercepted in the comments):

A UUID represents a 128-bit value

 * <p> There exist different variants of these global identifiers.  The methods
 * of this class are for manipulating the Leach-Salz variant, although the
 * constructors allow the creation of any variant of UUID (described below).
 *
 * <p> The layout of a variant 2 (Leach-Salz) UUID is as follows:
 *
 * The most significant long consists of the following unsigned fields:
 * <pre>
 * 0xFFFFFFFF00000000 time_low
 * 0x00000000FFFF0000 time_mid
 * 0x000000000000F000 version
 * 0x0000000000000FFF time_hi
 * </pre>
 * The least significant long consists of the following unsigned fields:
 * <pre>
 * 0xC000000000000000 variant
 * 0x3FFF000000000000 clock_seq
 * 0x0000FFFFFFFFFFFF node
 * </pre>
From this we can see:
1,UUID Represents a 128 bit value;
2,These universal identifiers have different variants. The methods of this class are used for operations Leach-Salz Variant, but the constructor allows you to create any UUID Variants (to be described below);
3,Variant 2 (Leach-Salz) UUID The layout of the is as follows: long The most significant bit of type data consists of the following unsigned fields:
 0xFFFFFFFF00000000 time_low
 0x00000000FFFF0000 time_mid
 0x000000000000F000 version
 0x0000000000000FFF time_hi
 
long The least significant bit of type data consists of the following unsigned fields:
 0xC000000000000000 variant
 0x3FFF000000000000 clock_seq
 0x0000FFFFFFFFFFFF node
 
variant Field contains a representation UUID The value of the layout. The bit layout described above is only available in UUID of variant A value of 2 indicates Leach-Salz Variant).

The version field holds a value that describes this UUID type. There are four different basic UUID types: time-based UUID, DCE security UUID, name based UUID, and randomly generated UUID. The version values for these types are 1, 2, 3, and 4, respectively.

For UUID documentation, refer to class UUID.

3.2 UUID version and related codes

version 1: time based UUID

public long timestamp() {
    if (version() != 1) {
        throw new UnsupportedOperationException("Not a time-based UUID");
    }

    return (mostSigBits & 0x0FFFL) << 48
         | ((mostSigBits >> 16) & 0x0FFFFL) << 32
         | mostSigBits >>> 32;
}

version 2: UUID of DCE security

Related documents: https://www.ietf.org/rfc/rfc4122.txt

The UUID algorithm of DCE (Distributed Computing Environment) security is the same as that of time-based UUID, but the first four positions of timestamp will be replaced by the UID or GID of POSIX. This version of UUID is rarely used in practice.

version 3: name based UUID

   public static UUID nameUUIDFromBytes(byte[] name) {
        MessageDigest md;
        try {
            md = MessageDigest.getInstance("MD5");
        } catch (NoSuchAlgorithmException nsae) {
            throw new InternalError("MD5 not supported", nsae);
        }
        byte[] md5Bytes = md.digest(name);
        md5Bytes[6]  &= 0x0f;  /* clear version        */
        md5Bytes[6]  |= 0x30;  /* set to version 3     */
        md5Bytes[8]  &= 0x3f;  /* clear variant        */
        md5Bytes[8]  |= 0x80;  /* set to IETF variant  */
        return new UUID(md5Bytes);
    }

version 4: random UUID

   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);
    }

version 5: name based UUID (SHA1)

3.3 UUID generation method

The following code is a typical method for generating UUIDs:

UUID uuid = UUID.randomUUID();
System.out.println(uuid);

The uuid result generated by the local test is: 744124dc-0e39-460b-8898-ba7285d796f5, which is a string of hexadecimal digits.

Because the string contains 36 characters and is relatively long, sometimes the getMostSignificantBits method of UUID will be used to retain only the most obvious 64bit, such as:

long uuid = UUID.randomUUID().getMostSignificantBits();
System.out.println(uuid);

The result is: - 3023758490243282597.

3.4 UUID uniqueness guarantee

Of the 128 bits of the Randomly generated UUID (for example, generated by the java.util.UUID class), 122 bits are randomly generated, 4 bits are used in this version ('Randomly generated UUID '), and 2 are used in its variant ('leach Salz'). Using the birthday paradox, it can be calculated that the probability that two UUIDs have the same value is about:

The following is the probability of collision after UUID is calculated with x=2^122:

It can be seen that the probability of generating duplicate guids and causing errors by random methods is very low.

3.5 is thread safe?

Let's take another look at the randomUUID() method of UUID:

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);

The focus is securerandom ng = holder numberGenerator; here. Holder location:

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

Seeing this, I believe some friends with solid foundation will think of an implementation of singleton mode, static internal class mode, which ensures thread safety when obtaining singleton instances.

Next is ng nextBytes(randomBytes);

    @Override
    public void nextBytes(byte[] bytes) {
        secureRandomSpi.engineNextBytes(bytes);
    }

SecureRandomSpi is an abstract class:

protected abstract void engineNextBytes(byte[] bytes);

SecureRandom is the implementation class of SecureRandomSpi. The implementation method is as follows:

    public synchronized void engineNextBytes(byte[] var1) {
        int var2 = 0;
        byte[] var4 = this.remainder;
        if (this.state == null) {
            byte[] var5 = new byte[20];
            SecureRandom.SeederHolder.seeder.engineNextBytes(var5);
            this.state = this.digest.digest(var5);
        }

        int var7 = this.remCount;
        int var3;
        int var6;
        if (var7 > 0) {
            var3 = var1.length - var2 < 20 - var7 ? var1.length - var2 : 20 - var7;

            for(var6 = 0; var6 < var3; ++var6) {
                var1[var6] = var4[var7];
                var4[var7++] = 0;
            }

            this.remCount += var3;
            var2 += var3;
        }

        while(var2 < var1.length) {
            this.digest.update(this.state);
            var4 = this.digest.digest();
            updateState(this.state, var4);
            var3 = var1.length - var2 > 20 ? 20 : var1.length - var2;

            for(var6 = 0; var6 < var3; ++var6) {
                var1[var2++] = var4[var6];
                var4[var6] = 0;
            }

            this.remCount += var3;
        }

        this.remainder = var4;
        this.remCount %= 20;
    }

The synchronized keyword in the method indicates that this is a synchronization method, and synchronization is realized through synchronized.

Uuid is immutable, so it may be thread safe, but obviously there are some evil caching going on in some accessors that make it unsafe (the bug has now been fixed). But the thread dump just says that a thread is waiting for securerandom The lock of nextbytes, which is controlled by Uuid Randomuuid is used by the factory, which is absolutely thread safe. As far as I know, this should happen when multiple threads call it at the same time.

Added by progwihz@yahoo.com on Thu, 20 Jan 2022 09:32:51 +0200