icella
7/12/2016 - 7:22 AM

Java – Ways to Generate Unique Ids in Java

Java – Ways to Generate Unique Ids in Java

Our previous solution, UID, generates unique strings on the host. They are not globally unique. So, two JVM instances may produce same UIDs. If you need universally unique identifiers you can use java.util.UUID (Universally Unique IDentifier) class.

The nextUUID() method below generates a different UUID (or GUID) string at each call (sample UUID: 251baa74-dc82-4e46-ae58-d7479c06eff5)

import java.util.UUID;
 
public class UUIDGenerator {
    public static String nextUUID() {
        return UUID.randomUUID().toString();
    }
}
Instances of java.rmi.server.UID class generates serializable identifiers which are unique on the host they are produced. The host must meet two conditions for uniqueness:

Reboot time must be greater than 1 millisecond
Its system clock is never set backward
The next class generates a different UID string at each nextUID() call (sample UID: -61bdd364:14a9f9c3782:-8000).

import java.rmi.server.UID;
 
public class UIDGenerator {
    public static String nextUID() {
        return new UID().toString()
    }
}
The simplest way of id generation is to maintain an id counter. The counter is actually an integer (mostly a Java long) that is incremented at each generation.

The IdCounter below, holds a counter and provides the synchronized nextId() method returning the next value of the counter. Synchronization is crucial to guard your counter against concurrent accesses in multithreaded applications.


public class IdCounter {
    private static long counter = 0;
 
    public static synchronized long nextId() {
        return ++counter;     
    } 
}
With Java 1.5+, a better way is using atomics like AtomicLong which are already thread-safe in nature. So, you don’t need an explicit synchronization.

import java.util.concurrent.atomic.AtomicLong;
 
public class AtomicIdCounter {
    private static AtomicLong counter = new AtomicLong(0);
 
    public static long nextId() {
        return counter.incrementAndGet();     
    } 
}
The object creation time can be set to object’s identifier property. For this purpose, System.currentTimeMillis() can be used. However, two or more objects may be created in a single millisecond. In this case, these objects will have the same id which is unacceptable. One way to cope with this problem is to use System.nanoTime(). Even if the nano time is the smallest interval we can use, it does not also guarantee the uniqueness. To provide unique time stamps, I got help from AtomicReference class as follows.

import java.util.concurrent.atomic.AtomicReference;
 
public class CurrentTimeId {
    private static AtomicReference<Long> currentTime = 
               new AtomicReference<>(System.currentTimeMillis());
 
    public static Long nextId() {
        return currentTime.accumulateAndGet(System.currentTimeMillis(), 
                   (prev, next) -> next > prev ? next : prev + 1)
    }
}
Note that accumulateAndGet method is available since Java 8. If you use earlier versions you can implement the following method.

import java.util.concurrent.atomic.AtomicReference;
 
public class CurrentTimeId {
    private static AtomicReference<Long> currentTime = 
               new AtomicReference<>(System.currentTimeMillis());
 
    public static Long nextId() {
        Long prev; 
        Long next = System.currentTimeMillis();
        do {
            prev = currentTime.get();
            next = next > prev ? next : prev + 1;
        } while (!currentTime.compareAndSet(prev, next));
        return next;
    }
}