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