18

We run Java 1.4.

We have this method:

static SimpleDateFormat xmlFormatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");

public static Date fromXml(String xmlDateTime) {
    ParsePosition pp = new ParsePosition(0);
    return xmlFormatter.parse(xmlDateTime, pp);
}

Where xmlDateTime = 2013-08-22T16:03:00 for example. This has been working, but suddenly stopped!

We now get this exception:

java.lang.ArrayIndexOutOfBoundsException: -1
at java.text.DigitList.fitsIntoLong(DigitList.java:170)
at java.text.DecimalFormat.parse(DecimalFormat.java:1064)
at java.text.SimpleDateFormat.subParse(SimpleDateFormat.java:1381)
at java.text.SimpleDateFormat.parse(SimpleDateFormat.java:1159) 

I have tried to reproduce this in a Unit Test by using different date formats, ie:

2013-08-22T16:03:00
2013-08-22 16:03:00

But no luck! Any ideas?

Andrew_CS
  • 2,542
  • 1
  • 18
  • 38
lulu88
  • 1,694
  • 5
  • 27
  • 41

4 Answers4

48

It is a little known fact that SimpleDateFormat is not threadsafe!

It is not a bug: The javadoc documents this behaviour:

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.

Create an instance every time you need one, or if performance is a real issue, you could try using ThreadLocal to store an instance for each thread that needs one.


Don't feel bad: I fell for exactly this "optimization" (to reuse a single constant instance), and to my amazement, had to instantiate a new instance every time.

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • When `joda-time` library is present then `DateTimeFormat`can be used. It's immutable and therefore threadsafe like everything in joda-time. btw +1 – Fabian Barney Aug 22 '13 at 14:45
  • I had the same issue on Android, but with formatting a date. How could it be that it's not thread safe? Seems to me that it should have a very generic algorithm inside, which doesn't need to assume anything about threads... – android developer Jan 08 '17 at 15:05
  • 2
    @android it's not threadsafe because the moron(s) who coded it decided to not make it threadsafe. Java 8's `DateTimeFormatter` et al *is* threadsafe however. – Bohemian Jan 08 '17 at 17:47
  • @Bohemian Sadly Java 8 is in very early stage on Android. I will just create a new instance per thread, using clone. – android developer Jan 08 '17 at 22:03
5

Looks like this bug report. The underlying reason was diagnosed to be that DecimalFormat simply isn't thread safe.

So you should not use the same SimpleDateFormat instance on different threads, since it, and DecimalFormat still aren't thread safe.

You could use ThreadLocal to have each thread use its own instance.

bowmore
  • 10,842
  • 1
  • 35
  • 43
1

Try using Commons Lang 3.x FastDateParser and FastDateFormat. These classes are thread safe and faster than SimpleDateFormat. They also support the same format/parse pattern specifications as SimpleDateFormat.

Chas
  • 371
  • 3
  • 5
1

A simple way to create instance each time, a local/scope variable instead of global variable, it works for me

private void test {
    SimpleDateFormat DATE_FORMAT = new SimpleDateFormat(pattern, Locale.ENGLISH);
    // Do somethings
}
Alen Lee
  • 2,479
  • 2
  • 21
  • 30