Reputation: 74
I have a logic to generate unique ID in java as below,
private static String generateUniqueNum()
{
final int LENGTH = 20;
final long uniqueNumber = abs(Long.valueOf(UUID.randomUUID().hashCode())) + System.currentTimeMillis() + abs(random.nextLong());
String value = Long.toString(uniqueNumber).replaceAll("-", "");
final int endIndex = value.length() <= LENGTH ? value.length() : LENGTH;
return String.format("MN%s", value.substring(0, endIndex));
}
private static Long abs(Long number){
if(null == number || 0 < number){
return 0L;
}
return Math.abs(number);
}
For the above code I have tested with jmeter with 3000 requests simultaneously and when I checked the result value generted, there are lot of duplicate valus generated. I dont know the reason how the duplicate value generated. Can someone has any idea on this.
Thanks in advance.
Upvotes: 1
Views: 1860
Reputation: 718906
Q: Why is your scheme giving significant non-uniqueness?
A: There is a howler of bug!
private static Long abs(Long number){
if(null == number || 0 < number){
return 0L;
}
return Math.abs(number);
}
If number
is less than zero, the 0 < number
means that this abs
method will returning zero as the "absolute" value.
Why does that matter? Well, your random number generation effectively does this:
long number = yourAbs(random int) + current time in millis + yourAbs(random long)
But because of your bug, there is a 50% probability that first term will be zero and a 50% probability that the last term will be zero.
So there is a 25% probablility, your "random" number will be the current time in milliseconds! Now suppose that you call generateUniqueNum()
twice in a millisecond .....
Oooops!!!
Note that without this bug, your code would still have a chance of 1 in 264 that any pair of numbers generated will be equal. If you then combine this with a "birthday paradox" analysis, the probability of any collisions becomes significant.
Upvotes: 1
Reputation: 44962
There are few problems with your current approach:
java.util.Random
is not thread-safe. If you have 3000 concurrent requests on different threads to the same Random
object you may get strange behavior. Try ThreadLocalRandom
instead.
Generated System.currentTimeMillis()
values will be close together if the 3000 concurrent requests are simultaneous.
Don't over complicate the problem, if you need a unique identifier:
UUID.randomUUID()
) or if you need stronger guarantees UUID v1. There is enough random bits in the UUID to guarantee that collisions are extremely unlikely.Upvotes: 1
Reputation: 109567
UUID is unique but uses 128 bits (two longs).
It would be best to use for a database key for instance the String representation. For a less safe long
:
return uuid.getLeastSignificantBits() ^ uuid.getMostSignificantBits();
Your clashes stem from hash code being an int (32 bits, a quarter), and combining with other properties will not necessarily make the number more random; even less so.
Upvotes: 3