Nim's Cynical Pleasantries Code, swords and a dirty mind!

3Aug/137

Java Date Performance Subtleties

A recent profling session pointed out that some of our processing threads were blocking on java.util.Date construction. This is troubling, because it's something we do many thousands of times per second, and blocked threads are pretty bad!

A bit of digging led me to TimeZone.getDefault(). This, for some insanely fucked up reason, makes a synchronized call to TimeZone.getDefaultInAppContext(). The call is synchronized because it attempts to load the default time zone from the sun.awt.AppContext. What. The. Fuck. I don't know what people were smoking when they wrote this, but I hope they enjoyed it ...

Unfortunately, Date doesn't have a constructor which takes a TimeZone argument, so it always calls getDefault() instead.

I decided to run some microbenchmarks. I benchmarked four different ways of creating Dates:

// date-short:
    new Date();
//date-long: 
    new Date(year, month, date, hrs, min, sec);
// calendar:
    Calendar cal = Calendar.getInstance(TimeZone);
    cal.set(year, month, date, hourOfDay, minute, second)
    cal.getTime();
// cached-cleared-calendar:
//    Same as calendar, but with Calendar.getInstance() outside of the loop, 
//    and a cal.clear() call in the loop.

I tested single threaded performance, where 1M Dates were created using each method in a single thread. Then multi-threaded with 4 threads, each thread creating 250k Dates. In other words: both methods ended up creating the same number of Dates.

Lower is beter.

Click to enlarge. Lower is beter.

With exception of date-long, all methods speed up by a factor of 2 when multi-threaded. (The machine only has 2 physical cores). The date-long method actually slows down when multi-threaded. This is because of lock contention in the synchronized TimeZone acquisition.

The JavaDoc for Date suggests replacing the date-long call by a calendar call. Performance-wise, this is not a very good suggestion: its single-threaded performance is twice as bad as that of Date unless you reuse the same Calendar instance. Even multi-threaded it's outperformed by date-long. This is simply not acceptable.

Fortunately, the cached-cleared-calendar option performs very well. You could easily store a ThreadLocal reference to an instance of a Calendar and clear it whenever you need to use it.

More important than the raw duration of the Date creation, is the synchronization overhead. Every time a thread has to wait to enter a synchronized block, it could end up being rescheduled or swapped out. This reduces the predictability of performance. Keeping synchronization down to a minimum (or zero, in this case) increases predictability and liveness of the application in general.

Before anyone mentions it: yes, I'm aware that the long Date constructors are deprecated. Unfortunately, they are what Joda uses when converting to Java Dates. I've proposed a patch, but while doing a bit more research for this blog post, I've come to the conclusion that my patch needs a bit of refining as it is still too slow (though it no longer blocks). In the mean while, I hope that the -kind?- folks at Oracle will reconsider their shoddy implementation.

I've also heard rumours that Joda will somehow, magically, replace java.util.Date in JDK 8. Not sure how that's going to work with backwards compatibility. I'd be much happier if java.util.Date would stop sucking quite as much. And if SimpleDateFormat were made thread-safe. And ... the list goes on.

flattr this!

Comments (7) Trackbacks (0)
  1. There is practically no compatibility between the “Joda” part and it won’t “magically replace” java.util.Date anywhere in the codebase ;-) It just adds (the biggest and fattest single package of Java 8 dedicated to just one API or JSR;-/) yet another Date/Time API and believe it or not, JavaFX, with SE 8 integral part of the JDK and aimed at replacing Swing has its own separate (and of course incompatible with at least java.time, there seem a few adapters to java.util.Date and Calendar though) Date/Time API. So 2 new/additional ones are added to Java 8 none replacing the old ones. Benchmarks by some performance-crazy folks from London did seem like java.time wasn’t doing very well either. Curious to see, if you get similar results on it or others do for Java 8, but don’t expect any miracle or magic on either of them I’m afraid ;-/

  2. That’s disturbingly disappointing. Sigh. I guess Java Date will just keep on sucking then ..

  3. Looking at the Date constructor source code I can’t see any calls to the TimeZone API.
    Where do you see the thread blocking call occurring?

    public Date() {
    this(System.currentTimeMillis());
    }

    public Date(long date) {
    fastTime = date;
    }

  4. The “fast” Date(long) constructor doesn’t call the TZ API. The slow, deprecated ones Date(field, field, field,..) do. Even though they’re deprecated, they’re still used a lot, by Joda Time among other things.

  5. This illustrates a problem, but does not offer a solution; why the article?

    1. The offending Date methods have been deprecated since the ancient Java 1.1, so WTF is any library still using them for, and why even use this code!
    2. Just blacklist libraries which use this cruft, and fix your code; bitching about this is pathetic.
    3. The offending Joda Time toDate() methods in the LocalDate and LocalDateTime classes are /deprecated/ too, because the developers are obviously to f’ing lazy to fix them!
    4. WTF are you pointlessly moaning about Oracle for, and not working around or fixing this yourself, using library fixes, caching, and ThreadLocal Calendar containers.

    Date and Calendar issues can be tamed, a Calendar can be managed by static utility methods to do lots of stuff which removes the need for complex APIs like Joda-time.

  6. 1. You’re right, they have been deprecated since forever, but Joda is still using them — probably because they’re more convenient than using Calendars? I’ve been meaning to revisit the Joda code but I haven’t got around to it yet.

    2. The Java Date API is a nightmare. Date sucks arse, Calendar is inconvenient. I use Joda Date/DateTime whenever I can, but in some projects I’m stick with Java Dates. Using Joda to do the heavy lifting eases the pain rather substantially, but at the cost of requiring conversions. These conversions, as illustrated, don’t perform very well in situations where you’re parsing thousands of dates/second.

    3. I can’t speak for the Joda developers, but I’m sure they’d welcome a patch or two ;).

    4. I’m moaning at Oracle/Sun because they’ve had a decade to improve the Date API, and instead of improving it they’ve made it worse. The most useful methods are deprecated, everything else is either confusing or a pain in the arse to use.

    Joda is only as complex as it needs to be (well, from an API point of view and the bits of code I’ve looked at, anyway). Dates and Time(zone)s are a giant paint in the cunt. I for one welcome any library that makes it better. Even more so if it’s thread safe, until like the Sun/Oracle abomination that is SimpleDateParser.

  7. We found exactly the same issue while profiling in a Tomcat container, with SoapUI sending JAX-WS messages, monitored with VisualVM which makes the ‘red’ blocked threads very apparent. We were able to very quickly remediate the issue by replacing Date.toString with the equivalent JodaTime call. The thread dump (JDK 1.6) is:

    java.lang.Thread.State: BLOCKED (on object monitor)
    at sun.awt.AppContext.get(AppContext.java:572)
    – waiting to lock (a java.util.HashMap)
    at sun.awt.AppContext$6.get(AppContext.java:774)
    at java.util.TimeZone.getDefaultInAppContext(TimeZone.java:637)
    at java.util.TimeZone.getDefaultRef(TimeZone.java:523)
    at java.util.Date.normalize(Date.java:1176)
    at java.util.Date.toString(Date.java:1010)


Leave a comment

No trackbacks yet.