March 24, 2009

SimpleDateFormat is not thread safe

It has always felt counter intuitive that there are classes which are not thread safe in the Sun JDK, but that is the case. One that I frequently see people trip up on is SimpleDateFormat. From the documentation:

Date formats are not synchronized. It is recommended to create separate format instances for each thread. If multiple threads access a format concurrently, it must be synchronized externally.

UPDATE

While SimpleDateFormat is not thread safe, as pointed out in the comments below, Spring seems to create new binders per request removing the need for this approach. In reviewing the documentation it isn't immediately clear that this is the case.

I recently had to create a custom editor for a Spring Web MVC command and ran into this issue. One possible fix, without introducing a ThreadLocal, is to just create a SimpleDateFormat every time. Hence this simple ThreadSafeSimpleDateFormat wrapper.

import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.ParsePosition;
import java.text.SimpleDateFormat;
import java.util.Date;

public class ThreadSafeSimpleDateFormat extends DateFormat {
    private String pattern;

    public ThreadSafeSimpleDateFormat(String pattern) {
        this.pattern = pattern;
    }

    @Override
    public StringBuffer format(Date date, StringBuffer toAppendTo, FieldPosition fieldPosition) {
        return new SimpleDateFormat(pattern).format(date, toAppendTo, fieldPosition);
    }

    @Override
    public Date parse(String source, ParsePosition pos) {
        return new SimpleDateFormat(pattern).parse(source, pos);
    }
}

Then to setup that as the editor handler for a command that has a date field, in my controller that uses the command I added the following:

@Override
protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
    super.initBinder(request, binder);
    binder.registerCustomEditor(Date.class, DATE_TIME, new CustomDateEditor(new ThreadSafeSimpleDateFormat(DATE_TIME_FORMAT), false));
}


Tags: date java spring