pátek 13. února 2015

Java: Fast Date Formatting in Web Containers

Java SimpleDateFormat is not thread safe. When it is used in multithreaded applications, like Java web containers, it's forbidden use it as a static constant
public static final DateFormat DATE_FORMAT = new SimpleDateFormat('YYYY.MM.dd'); // DON'T!
Most developers properly constructs new SimpleDateFormat everytime they need
DateFormat dateFormat = new SimpleDateFormat('YYYY.MM.dd');
String str = dateFormat.format(date);
However, constructing new SimpleDateFormat is not so cheap operation. So, how to safe CPU and memory like in static final pattern in a multithreaded environment?

Solution 1: clone


Fortunatelly, SimpleDateFormat implements clone() method, which is fasters than constructing a new one form a String:
private static final DateFormat DATE_FORMAT_TEMPLATE = new SimpleDateFormat('YYYY.MM.dd'); // Do not use directly

/**
 * @return every time a new SimpleDateFormat.
 */
public static DateFormat getDateFormat() {
 return DATE_FORMAT_TEMPLATE.clone();
}

Solution 2: ThreadLocal


A general solution for sharing non-thread safe objects is to have one copy for each thread. Java has a very nice ThreadLocal. Together with lazy initialization we got the proper thread safe and fast solution:
private static final ThreadLocal DATE_FORMAT_TL = new ThreadLocal() {
 protected DateFormat initialValue() {
  return new SimpleDateFormat('YYYY.MM.dd');
 };
};

/**
 * @return SimpleDateFormat, new one for every thread.
 */
public static DateFormat getDateFormat() {
 return DATE_FORMAT_TL .get();
}

/**
 * Simple, optimized Date formatting.
 */
public static String format(Date d) {
 return format == null ? null : getDateFormat().format(d);
}
This solution has advantage over clone() method, that calling getDateFormat() multiple times in one thread (e.g. inside a loop) does not create a new object. I like to add format() to simplify usage and handle null values. Note: ThreadLocal may cause redeploy memory leaks when it's value from a WAR class. E.g. see Java Web Container: Hunting Redeploy Memory Leaks