Nithyananth
Nithyananth

Reputation: 74

Generating unique value in java give duplicate

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

Answers (3)

Stephen C
Stephen C

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

Karol Dowbecki
Karol Dowbecki

Reputation: 44962

There are few problems with your current approach:

  1. 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.

  2. 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:

  1. Use UUID v4 (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.
  2. If you need something more concise maintain a shared counter e.g. database sequence. Simply increment by one each time you want new unique number.

Upvotes: 1

Joop Eggen
Joop Eggen

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

Related Questions