How to generate unique ID numbers on a multithread application??
Assumptions:
- Generated ID are unique
- Minimal synchronization between thread
- No synchronization between thread during generation
- No order assumed, just different values
Ids generated from primes
The idea is to generate the ids as product of powers of prime numbers
id = p_1^f1 * p_2^f2 * p_2^f3 * ... * p_n^fn
We use different prime numbers in each thread to generate different sets of ids in each thread.
Assuming that we use primes (2,3,5), the sequence will be:
2, 2^2, 2^3, 2^4, 2^5,..., 2^64
Then, when we see that a overflow will be generated, we roll the factor to the next prime:
3, 2*3 , 2^2*3, 2^3*3, 2^4*3, 2^5*3,..., 2^62*3
Generation class
Each instance of class IdFactorialGenerator will generate different sets of ids.
To have a thread save generation of Ids, just use ThreadLocal
package eu.pmsoft.sam.idgenerator; public class IdFactorialGenerator { private static AtomicInteger nextPrimeNumber = 0; private int usedSlots; private int[] primes = new int[64]; private int[] factors = new int[64]; private long id; public IdFactorialGenerator(){ usedSlots = 1; primes[0] = Sieve$.MODULE$.primeNumber(nextPrimeNumber.getAndAdd(1)); factors[0] = 1; id = 1; } public long nextId(){ for (int factorToUpdate = 0; factorToUpdate < 64; factorToUpdate++) { if(factorToUpdate == usedSlots) { factors[factorToUpdate] = 1; primes[factorToUpdate] = Sieve$.MODULE$.primeNumber(nextPrimeNumber.getAndAdd(1)); usedSlots++; } int primeToExtend = primes[factorToUpdate]; if( primeToExtend < Long.MAX_VALUE / id) { // id * primeToExtend < Long.MAX_VALUE factors[factorToUpdate] = factors[factorToUpdate]*primeToExtend; id = id*primeToExtend; return id; } else { factors[factorToUpdate] = 1; id = 1; for (int i = 0; i < usedSlots; i++) { id = id*factors[i]; } } } throw new IllegalStateException("I can not generate more ids"); } }
To get the prime numbers I use a implementations on scala provided here in the problem 7: http://pavelfatin.com/scala-for-project-euler/
object Sieve { def primeNumber(position: Int): Int = ps(position) private lazy val ps: Stream[Int] = 2 #:: Stream.from(3).filter(i => ps.takeWhile(j => j * j <= i).forall(i % _ > 0)) }
Comments
Post a Comment