I need to generate a 64 bit unique integer in Java. I need to make sure that there is very few or no collisions if possible.
I came up with the below code which works fine:
public class TestUniqueness {
private static final AtomicLong TS = new AtomicLong();
public static void main(String[] args) {
// for testing, just added the for loop
for (int i = 1; i <= 100000; i++) {
System.out.println(getUniqueTimestamp());
}
}
public static long getUniqueTimestamp() {
long micros = System.currentTimeMillis() * 1000;
for (;;) {
long value = TS.get();
if (micros <= value)
micros = value + 1;
if (TS.compareAndSet(value, micros))
return micros;
}
}
}
I will be running the above code in production.
3 Answers 3
My specification is only to generate the 64 bit unique integer, that's it.
In this case, there's no need for anything more complicated than atomically incrementing a counter:
public class Counter {
private static final AtomicLong counter = new AtomicLong(0);
public static long getNextNumber(){
return counter.incrementAndGet();
}
}
To offer a more specific critique of your code, it's unnecessarily complicated and inefficient. I don't see anything incorrect about it (i.e. it seems like it meets your criteria), but there's the old saying about obviously no bugs vs no obvious bugs (paraphrased).
-
\$\begingroup\$ If this is a code that runs in a server that can go down and needs to be restarted, then I think that it would be good to set the initial time of AtomicLong to the current system time. In that way, when the server is restarted, it does not even repeat on values that it generated before being restarted. \$\endgroup\$ASDF– ASDF2015年09月15日 17:18:38 +00:00Commented Sep 15, 2015 at 17:18
-
1\$\begingroup\$ @JadieldeArmas That won't work, you will get conflicts eventually. If you're incrementing from a timestamp, and then restart in the future, the new starting timestamp has a chance of being a number you previously used. It's much better to lookup the last max value and then restart from there. \$\endgroup\$Mani Gandham– Mani Gandham2017年01月10日 21:48:48 +00:00Commented Jan 10, 2017 at 21:48
Just some points:
for (;;) {
long value = TS.get();
if (micros <= value)
micros = value + 1;
if (TS.compareAndSet(value, micros))
return micros;
}
Here, I suggest you do while(true)
instead of for(;;)
. It is a matter of preference, but I think while(true)
is easier to understand.
Also, always put braces for if
statements. If you don't, horrible bugs may occur. Here is an example:
Say you have this if
statement:
if(isSomething())
doSomething();
And then you decide that the code has to do something else in the if
statement:
if(isSomething())
doSomething();
doSomethingElse();
Now you have a horrible bug. It looks fine, but when you run it, doSomethingElse()
will execute no matter what isSomething()
returns. If you actually had braces:
if(isSomething()) {
doSomething();
}
Then:
if(isSomething()) {
doSomething();
doSomethingElse();
}
That should work fine.
Is there any reason why you are not using the Apache library?
The RandomStringsUtils
library provides a method for creating a random number.
The best part: you specify the range.
By the way, the method is randomNumber()
-
\$\begingroup\$ Looks ok, but I need to have uniqueness. Random doesn't mean unique. \$\endgroup\$david– david2015年02月06日 22:11:23 +00:00Commented Feb 6, 2015 at 22:11
random
but you are just getting the current time without repeats, which doesn't qualify as random in my book. \$\endgroup\$System.nanoTime()
(Don't see relation to tag random) \$\endgroup\$