danieln
danieln

Reputation: 4973

Generate ID fast and with high probability of uniqueness

I want to generate ID to event that occur in my application.

The event frequency is up to the user load, so it might occur hundreds-thousand of time per second.

I can't afford using UUID.randomUUID() because it might be problematic in performance matters - Take a look at this.

I thought of generating ID as follows:

System.currentTimeMillis() + ";" + Long.toString(_random.nextLong())

When _random is a static java.util.Random my class is holding.

My questions are:

  1. Do you think the distribution of this combination will be good enough to my needs?
  2. Does Java's Random implementation related to the current time and therefore the fact I'm combining the two is dangerous?

Upvotes: 10

Views: 5514

Answers (5)

Julien Kronegg
Julien Kronegg

Reputation: 5251

I would use a library to avoid reinventing the wheel.

For example, JUG (https://github.com/cowtowncoder/java-uuid-generator) can generate 5 millions time-based UUIDs per second (https://github.com/cowtowncoder/java-uuid-generator/blob/master/release-notes/FAQ) :

<dependency>
  <groupId>com.fasterxml.uuid</groupId>
  <artifactId>java-uuid-generator</artifactId>
  <version>4.0.1</version>
</dependency>

UUID uuid = Generators.timeBasedGenerator().generate();

Upvotes: 0

Peter Lawrey
Peter Lawrey

Reputation: 533500

I would use the following.

final AtomicLong counter = new AtomicLong(System.currentTimeMillis() * 1000);

and

long l = counter.getAndIncrement(); // takes less than 10 nano-seconds most of the time.

This will be unique within your system and across restarts provided you average less than one million per second.

Even at this rate, the number will not overflow for some time.

class Main {
    public static void main(String[] args) {
        System.out.println(new java.util.Date(Long.MAX_VALUE/1000));
    }
}

prints

Sun Jan 10 04:00:54 GMT 294247

EDIT: In the last 8 years I have switched to using nanosecond wall clock and memory-mapped files to ensure uniqueness across processes on the same machine. The code is available here. https://github.com/OpenHFT/Chronicle-Bytes/blob/ea/src/main/java/net/openhft/chronicle/bytes/MappedUniqueTimeProvider.java

Upvotes: 8

Aaron Digulla
Aaron Digulla

Reputation: 328594

I can't afford using UUID.randomUUID() because it might be problematic

And it might not. Currently, you're solving a problem that might not exist. I suggest to use an interface so you can easily swap out the generated ID but stick to this generator on which many smart people have spent a lot of time to make it right.

Your own solution might work in many cases but the corner cases are important and you will only see those after a few years of experience.

That said, combining the current time + Random should give pretty unique IDs. But they are easy to guess and insecure.

Upvotes: 2

Joop Eggen
Joop Eggen

Reputation: 109547

UUID uuid = UUID.randomUUID(); is less than 8 times slower, after warming up, 0.015 ms versus 0.0021 ms on my PC. That would be a positive argument for UUID - for me.

  1. One could shift the random long a bit to the right, so time is more normative, sequencing.
  2. No, there is a pseudo random distribution involved.

Upvotes: 2

destan
destan

Reputation: 4411

To prevent possible collisions I would suggest you to somehow integrate users' unique ids into the generated id. You can do this either adding user id to directly to the generated id

System.currentTimeMillis() + ";" + Long.toString(_random.nextLong()) + userId

or you can use separate _random for each user that uses the user's id as its seed.

Upvotes: 3

Related Questions