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 needDateFormat 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 ThreadLocalThis solution has advantage over() { 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); }
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