Wednesday, October 10, 2007
It never fails to surprise me that so many developers are unaware that SimpleDateFormat is not thread-safe. It seems like almost all J2EE projects I work on have code that uses instance variables or static instance variables to store a SimpleDateFormat that is then used throughout the code base without any concurrency control. Here’s a classic example:public class MyService // could be a web service or a session beanThis is particularly nasty because the code may well run without producing any exceptions but could easily parse the date incorrectly. If you don't believe how likely this is, here's some code to prove the point:
{
public void someBusinessMethod(String datestring, ...) {
Date date = GlobalConst.DATE_FMT.parse(datestring);
// rest of code omitted
}
}
public class ProveNotSafe {
static SimpleDateFormat df
= new SimpleDateFormat( "dd-MMM-yyyy" );
static String testdata[] = {
"01-Jan-1999", "14-Feb-2001", "31-Dec-2007"
};
public static void main(String[] args) {
Runnable r[] = new Runnable[ testdata.length ];
for (int i = 0; i < r.length; i++) {
final int i2 = i;
r[i] = new Runnable() {
public void run() {
try {
for (int j=0; j<1000; j++) {
String str = testdata[i2];
String str2 = null;
/*synchronized(df)*/ {
Date d = df.parse(str);
str2 = df.format( d );
}
if (!str.equals(str2)) {
throw new RuntimeException(
"date conversion failed after "
+ j + " iterations. Expected "
+ str + " but got " + str2 );
}
}
} catch (ParseException e) {
throw new RuntimeException( "parse failed" );
}
}
};
new Thread(r[i]).start();
}
}
}
java.lang.RuntimeException: date conversion failed after 3 iterations.Note that "01-Dec-2007" isn't even one of the strings in the test data. It is actually a combination of the dates being processed by the other two threads!
Expected 14-Feb-2001 but got 01-Dec-2007
public class ThreadSafeSimpleDateFormat {
private DateFormat df;
public ThreadSafeSimpleDateFormat(String format) {
this.df = new SimpleDateFormat(format);
}
public synchronized String format(Date date) {
return df.format(date);
}
public synchronized Date parse(String string) throws ParseException {
return df.parse(string);
}
}
Come from : http://www.codefutures.com/weblog/andygrove/2007/10/simpledateformat-and-thread-safety.html