I had similar issue (16 digits in my case) and didn't found a good solution so i created one here
Idea
This utility works like clock, so you get unique random numbers per installation. we generate 16 digit integer value for example 2226015501234239
Implementation
import java.math.BigInteger;
import java.time.LocalDateTime;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
public class App {
private Set set = new HashSet<BigInteger>();
private String flag = mostSignificantCounter();
private String mostSignificantCounter() {
LocalDateTime localDateTime = LocalDateTime.now();
return new StringBuilder()
.append((localDateTime.getYear() + "").substring(2))
.append(localDateTime.getDayOfYear())
.append(localDateTime.getHour())
.append(localDateTime.getMinute())
.append(localDateTime.getSecond())
.toString();
}
private String leastSignificantCounter() {
Random random = new Random(LocalDateTime.now().getNano());
Integer rId = (1 + random.nextInt(10) * 10000) + random.nextInt(10000);
return String.format("%05d", rId);
}
public BigInteger uniqueRandomBigInt() {
String msc = mostSignificantCounter();
BigInteger uniqueBigIntId = new BigInteger(msc + leastSignificantCounter());
if (set.contains(uniqueBigIntId)) {
return uniqueRandomBigInt();
} else {
if (!flag.equals(msc)) {
set.clear();
flag = msc;
}
set.add(uniqueBigIntId);
return uniqueBigIntId;
}
}
}
Stress test
@Test
public void testApp() {
Long startTime = System.currentTimeMillis();
App app = new App();
while ((System.currentTimeMillis() - startTime) < (1000 * 60)) {
BigInteger uniqueRandomBigInt = app.uniqueRandomBigInt();
assertFalse(
testSet.contains(uniqueRandomBigInt),
"Failed to generate unique random ID, found duplicate -> " + uniqueRandomBigInt
);
testSet.add(uniqueRandomBigInt);
}
assertTrue(true);
}