SoFunction
Updated on 2025-03-01

Summary of three ways to generate unique IDs in Java

Generate unique ID using AtomicLong (for single airport view)

This example has been given in the previous answer, but I will show it again to maintain consistency with subsequent examples.

import ;  
  
public class UniqueIdGenerator {  
    private final AtomicLong counter = new AtomicLong(0);  
  
    public long nextId() {  
        return ();  
    }  
  
    public static void main(String[] args) {  
        UniqueIdGenerator generator = new UniqueIdGenerator();  
        long id1 = ();  
        long id2 = ();  
        ("ID 1: " + id1);  
        ("ID 2: " + id2);  
    }  
}

Use UUID and convert to numeric form (although not pure numeric, but provides uniqueness)

Since the UUID itself is in the form of a string, we can convert it to a number through a hash function (such as MD5, SHA-1, etc.), but we need to pay attention to the possibility of hash collisions (although very low in practical applications). However, it is more common to preserve the string form of the UUID or use it as a basis to generate a digital ID that meets a specific need.

import ;  
  
public class UuidToNumberExample {  
    // Note: This is not an effective way to convert the UUID directly to a unique number, because there is a risk of hash collisions.    // This is just to illustrate the concept.  
    public static long uuidToNumber(UUID uuid) {  
        // Simple example: Combine the string representation of the UUID with another number and hash it (note: this is not a safe practice)        String uuidStr = ();  
        long base = 123456789L; // The hypothetical cardinality        // This is not implemented here, but uses string length plus cardinality as an example (for demonstration only)        return () + base; // This is not a good implementation!  
        // A more practical approach is to use a safe hash function, but be aware of the possibility of hash collisions        // And, since the output of the hash function is of a fixed length, direct use as an ID may require further processing    }  
  
    public static void main(String[] args) {  
        UUID uuid = ();  
        long number = uuidToNumber(uuid); // The implementation here is wrong, only for explanation        ("UUID: " + uuid);  
        ("Converted Number (Incorrect Method): " + number);  
  
        // The correct approach might be to use UUIDs as the basis for finding or generating more complex IDs    }  
}

Simulate Snowflake algorithm to generate unique ID (distributed scenario)

The implementation of the Snowflake algorithm is relatively complex, but we can simplify its core idea to demonstrate a basic framework.

public class SnowflakeIdWorker {  
    // Assumptions of timestamp, data center ID, machine ID and serial number fields (requires more refined management in actual applications)    private final long twepoch = 1288834974657L; // Custom start timestamp    private final long datacenterIdBits = 5L; // Number of ID digits in the data center    private final long maxDatacenterId = -1L ^ (-1L << datacenterIdBits); // Maximum data center ID value    private final long workerIdBits = 5L; // Number of machine ID bits    private final long maxWorkerId = -1L ^ (-1L << workerIdBits); // Maximum value of machine ID    private final long sequenceBits = 12L; // Number of serial numbers  
    private final long workerIdShift = sequenceBits; // The left shift number of machine ID    private final long datacenterIdShift = sequenceBits + workerIdBits; // Data center ID left shift number    private final long timestampLeftShift = sequenceBits + workerIdBits + datacenterIdBits; // The number of timestamp shifts left  
    private long sequence = 0L; // Serial number    private long lastTimestamp = -1L; // The time stamp of the last ID generated  
    // Initialize workerId and datacenterId in the constructor (here is an example, which should be specified externally in practice)    public SnowflakeIdWorker(long workerId, long datacenterId) {  
        if (workerId > maxWorkerId || workerId < 0) {  
            throw new IllegalArgumentException(("worker Id can't be greater than %d or less than 0", maxWorkerId));  
        }  
        if (datacenterId > maxDatacenterId || datacenterId < 0) {  
            throw new IllegalArgumentException(("datacenter Id can't be greater than %d or less than 0", maxDatacenterId));  
        }  
        // The steps to actually set workerId and datacenterId into the object are omitted here    }  
  
    // Method for generating ID (simplified version, not including clock callback processing, etc.)    public synchronized long nextId() {  
        long timestamp = timeGen();  
  
        // If the current time is less than the timestamp generated by the last ID, it means that the system clock has called back        if (timestamp < lastTimestamp) {  
            throw new RuntimeException(("Clock moved backwards. Refusing to generate id for %d milliseconds", lastTimestamp - timestamp));  
        }  
  
        // If it is generated at the same time, a sequence within milliseconds will be performed        if (lastTimestamp == timestamp) {  
            sequence = (sequence + 1) & (-1L ^ (-1L << sequenceBits));  
            if (sequence == 0) {  
                // Sequence overflow within milliseconds                timestamp = tilNextMillis(lastTimestamp);  
            }  
        } else {  
            // The timestamp changes, the sequence is reset within milliseconds            sequence = 0L;  
        }  
  
        // The time stamp of the last ID generated        lastTimestamp = timestamp;  
  
        // Shift and use or compute to form a 64-bit ID        // The left shift sum or operation of the actual workerId and datacenterId are omitted here        // Example: return ((timestamp - twepoch) << timestampLeftShift) | (datacenterId << datacenterIdShift) | (workerId << workerIdShift) | sequence;        return 0L; // Returns the simulated 0, and the ID calculated in the above method should actually be returned    }  
  
    // Simulate to get the current time stamp of the system (milliseconds)    protected long timeGen() {  
        return ();  
    }  
  
    // Wait until the next millisecond to get a new time stamp    protected long tilNextMillis(long lastTimestamp) {  
        long timestamp = timeGen();  
        while (timestamp &lt;= lastTimestamp) {  
            timestamp = timeGen();  
        }  
        return timestamp;  
    }  
  
    // Omit the main method and other possible auxiliary methods...}

Please note that the implementation of the above Snowflake algorithm is highly simplified and omits many key details (such as the settings of the actual data center ID and machine ID, the correct processing of the serial number, and the detailed processing logic of clock callback). In practical applications, you need to fully implement these functions according to your needs and environment.

Summarize

In a stand-alone environment, AtomicLong can be used to generate a unique ID; while in scenarios where non-pure digital forms are required, UUID can be combined with hash functions such as MD5 or SHA-1 to convert them into numbers, but attention should be paid to the low probability risk of hash collisions; for distributed systems, simulated Snowflake algorithm is a complex but effective method, and each method has its applicable scenarios and potential problems, and it is necessary to select a suitable implementation method according to specific needs and environment.

This is the end of this article about the three methods of generating unique IDs in Java. For more related content on generating unique IDs in Java, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!