Categories

Thread safety issues with Java SimpleDateFormat class

One of the common programming practices is to define a static SimpleDateFormat instance and use it in your application whenever you need to parse and/or format Java dates. It actually does perfect sense, because parsing and formatting in general is a computationally expensive operation and rather than creating the object over and over again, it is a lot more efficient to create one and to reuse it. After all converting one object to another is quite a trivial task, or is it?

One of the applications I developed was corrupting data every now and then, and I always assumed it is a temporary system failure or unavailable database. When this became a real issue I bothered to investigate further and the problem turned out to be one of the most common (well not common enough for me to pay attention I guess) thread safety issues of core Java classes. If you’re thinking your code is not multi-threaded and you don’t need to care about this, think again because most application servers (Tomcat, JBoss, etc.) create multiple threads without you even knowing about it.

As this is a pretty easy mistake to make, I decided to document the solution here…

The mistake:

I had a static variable to define a central date format, which I used through out my application.

public static final SimpleDateFormat DEFAULT_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");

So when I need to parse a date, or format it I simple make a single line call to:

Constants.DEFAULT_FORMAT.parse(date);

It is nice and clean, and when in doubt I can always go to the Constants class to see what the date format looked like.

The problem:

The above should work fine in a single threaded application, or even in a multi-threaded application if the date formatting and parsing is not very heavily used. That’s what makes it elusive. The problem is not that it always throws an exception, but when two or more threads try to use the same static variable at the same time, the method returns some arbitrary date, so your code has no way of knowing if the date is wrong or not.

The solution:

Whatever I’ve documented so far is actually well publicized. The consensus on the solution is essentially:

  1. Don’t use it. Create a new SimpleDateFormat instance whenever you need it. This doesn’t work me as latency is very critical and can’t effort to have the object recreated every single time. I also hate to lose the centrally managed, well documented repository of all date formats in my Constants class.
  2. Synchronize it, which essentially will make your threads wait for each other to access this class, potentially creating a big bottleneck. So this is a no go as well.
  3. Use ThreadLocal, which is what I did. As there are not many examples out there to demonstrate how to use it I wanted to document a simple example for your convenience.

You better refer to Java documentation for a better description of ThreadLocal class, but it essentially creates one static variable per thread rather than per application. You’ll need to slightly change both your variable definition and how you access it, but the change is quite systematic, and you can do it safely with the help of a good IDE and the good old find/replace utility.

First replace your static variable with the following:

// public static final SimpleDateFormat DEFAULT_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
public static final ThreadLocal<SimpleDateFormat> DEFAULT_FORMAT = new ThreadLocal<SimpleDateFormat>() {
  @Override
  protected SimpleDateFormat initialValue() {
    return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
  }
};

Note that this method is will no longer return you SimpleDateFormat, but rather the ThreadLocal instance which contains it. So you’ll have to make a minor modification to all references to your old variable:

//Constants.DEFAULT_FORMAT.parse(date);
Constants.DEFAULT_FORMAT.get().parse(date);

And that’s pretty much it. A good IDE should highlight all references once you change the static variable so it’s not hard to find them.

While you are at it, I would check if there are other static variables that are known to be non-thread-safe and replace them as well.
In my case I also needed to convert some other decimal formatters.

//public static final DecimalFormat TWO_DIGIT_MONEY_FORMAT = new DecimalFormat("#,##0.00");
public static final ThreadLocal<DecimalFormat> TWO_DIGIT_MONEY_FORMAT = new ThreadLocal<DecimalFormat>() {
  @Override
  protected DecimalFormat initialValue() {
    return new DecimalFormat("#,##0.00");
  }
};

PS: One of the online bloggers commented that this solution would have issues in thread pools. I’m not sure what his/her rationale was, but I’ve been using it with pooled threads quite a while now and didn’t have any problems so far. I profiled the application memory for half a day just to make sure that I’m not leaking any memory. I’ll update this entry if I encounter any issues.

  • Share/Bookmark

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>