4

Imagine i have a proccess that creates 1000 entities each second. for each of these entities i call the setter :

newEntity.setDate(new Date());

1) Is it possible that 2 entities will recieve the same date? or is it safe to assume that i do get a unique identifier effect for the date field?

2) If the answer to question #1 is :"yes" - let's make a minor tweak: lets create a function:

public static synchronized Date getDate() {
     return new Date();
}

will it work now?

newEntity.setDate(getDate());

3) what about

System.nanoTime()?

EDIT 4) what about :

public static synchronized Date getDate() {
     Thread.Sleep(1000);
     return new Date();
}

thanks.

Urbanleg
  • 6,252
  • 16
  • 76
  • 139
  • 2
    `new Date()` reads the system clock - it's possible to make multiple reads within the same millisecond. Synchronizing won't change that (except to make the time it takes to complete an operation marginally longer). Don't use a date as a unique identifier. – Greg Kopff Jul 31 '13 at 12:51

4 Answers4

10

A simple test shows that two consecutive calls to new Date() can return the same date. Making the method synchronized won't make any difference.

If all you need is a unique ID, you could use an AtomicInteger counter and return counter.getAndIncrement(); for new ids.

ps: using System.nanotime() won't help either as the resolution is os and processor dependent and is generally low enough that two consecutive calls can return the same result too.


EDIT

Your 4th proposal to sleep for a second in a synchronized method would probably solve your unicity issue (although as pointed out by yshavit, nothing in the javadoc guarantees it). Note however that using a Date as a unique id is a bad idea in itself: Dates are mutable so the calling code could change its id with the setTime method (by mistake or on purpose).

Finally, if you really want your id to be date related, you could use a long representing milliseconds since the epoch and keep track of the existing ids - something like this:

private static final Set<Long> usedIds = new HashSet<> ();
public static synchronized long getUniqueId() {
    long millis;
    do {
        millis = System.currentTimeMillis();
    } while (!usedIds.add(millis));
    return millis;
}
assylias
  • 321,522
  • 82
  • 660
  • 783
  • 1
    It's also worth nothing that sleeping for a second is at odds with one of the opening parameters of the question, that the process "creates 1000 entities each second". It's going to be hard to create 1000 entities each second if each one takes at least a second to create. – yshavit Jul 31 '13 at 13:16
  • +1 at once for "Making the method synchronized won't make any difference"!! – Andremoniy Jul 31 '13 at 13:44
4

Date has millisecond precision. So this boils down to, "is it possible to invoke new Date() twice in a millisecond? The answer is obviously yes. In addition, System.currentTimeMillis() is not completely accurate to the millisecond, which only makes the problem worse.

You'd be better off with a simple counter from AtomicInteger (or AtomicLong).

In addition, this is a good exercise in "design by contract" mentality. The specification for neither currentTimeMillis nor nanoTime say that they'll return unique numbers, so you can't assume they will (in fact, the Javadoc for nanoTime specifically says that "no guarantees are made about how frequently values change"). Even if they happened to on your computer today (they probably don't), what happens when CPUs get faster in 5 years and you're able to invoke nanoTime() a trillion times a second?

Go on what you've been promised (assuming you trust the promise!), not with what you happen to observe today. This is generally true, but especially so of anything related to timing or concurrency.

Community
  • 1
  • 1
yshavit
  • 42,327
  • 7
  • 87
  • 124
0

1) If your CPU is fast enough, yes, it is possible that two entities receive different objects representing the same time (i. e. it wont work the way you want)

2) Again, if your CPU is fast enough, it won't work.

morgano
  • 17,210
  • 10
  • 45
  • 56
0

Unfortunately 1. is not a good solution
your proposal are all not ok as formulated.
In the synchronized method you could add a sleep with the correct granularity (1 millisec): very ugly anyway.
Your other proposal.
System.nanotime() I guess should be your uuid now, so a long.
In this case a workaround could be setting a delay to 1 nanosec and:

long start = System.nanotime();  
while(start + delay < System.nanoTime());  
blackbird014
  • 2,069
  • 1
  • 18
  • 23