0

I am working on a servlet where i need to provide a unique request to each request and store each request params in an audit table. I am worried of dirty read operations on database tables if i try to increment a value by looking back the table for the previous id. I want to know if if using time in milli seconds when the request is arrived in servlet to solve this. I am afraid if there can be any other request coming from other geography location at same time for the same servlet so that the java.lang.System.currentTimeMillis() will be same for the other request coming. The reason which made me post this doubt is i believe the multithreading behavior of servlet is taking a request at a time and then spanning cpu cycles for each request based on some algorithm.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
user1036204
  • 175
  • 1
  • 2
  • 12
  • 1
    if you had a synchronized block of code, where you obtained your `key`, then you could control this. – Scary Wombat Jan 05 '16 at 08:47
  • Thanks for raising about synchronization blocks but i am worried of performance issues so only i was thinking if we can use time in millis. What is your comment on the java.lang.System.currentTimeMillis() value to be unique for different request arrived at same time for the same servlet. – user1036204 Jan 05 '16 at 08:51
  • 1
    The time in milliseconds is not guranteed to be unique. On some OS it may even increment in larger chunks. – Henry Jan 05 '16 at 08:53
  • Thanks for confirming on this. I will try to compromise with synchronized (this) { } and achieve the logic – user1036204 Jan 05 '16 at 08:55

2 Answers2

3

The System.currentTimeMillis() is not guaranteed to be unique when called by multiple threads. When faced with this situation in the past I've used an AtomicLong to create unique ids - this class's getAndIncremenet should be lock-free (and hence reasonably efficient) on most JVMs

public class IdUtil {
    private static final AtomicLong counter = new AtomicLong(System.currentTimeMillis());

    // return a single id
    public static long getId() {
        return counter.getAndIncrement();
    }

    // return a block of ids
    public static Queue<Long> getIds(long span) {
        long max = counter.addAndGet(span);
        Queue<Long> queue = new ArrayDeque<>(span);
        for(int i = max - span; i < max; i++) {
            queue.add(i);
        }
    }
}
Zim-Zam O'Pootertoot
  • 17,888
  • 4
  • 41
  • 69
0

Even synchronized it is wrong. You may get the same ID for two requests very close in time. You should better use a random long or sequential number.

private static final Random r = new Random(); // <- shared resource
// ...
long id = r.nextLong();

or

private static final AtomicLong counter = new AtomicLong(System.currentTimeMillis()); // <- shared resource
// ...
long id = counter.getAndIncrement();

counter is initialized with milliseconds so it does not provide the same id sequence after program restart.

aalku
  • 2,860
  • 2
  • 23
  • 44
  • Interesting now i got a new way after reading your comment, If i use the above method, is there a chance that one day i get same id for two different requests on different dates. In that case i can use this ID and timestamp as unqiue key to identify a unique request – user1036204 Jan 05 '16 at 09:09
  • There are 18,446,744,073,709,551,616 different long values. The risk of ID collision is really really really low. You would need to process billions of transactions every day and the chance would still be quite low. – aalku Jan 05 '16 at 11:27