2

I have a number of Java date patterns and want to reuse them multiple times in SimpleDateFormat objects across different threads, via static references, for speed.

The code would look something like this (inside a class called, say, FormatClass):

private static String[] PATTERNS = new String[] {...};

public ThreadLocal<SimpleDateFormat[]> LOCAL_FORMATS = new ThreadLocal<SimpleDateFormat[]>
{
    @Override
    protected SimpleDateFormat[] initialValue()
    {
        List<SimpleDateFormat> formatList = new ArrayList<SimpleDateFormat>();

        for (String pattern:PATTERNS)
        {
            formatList.add(new SimpleDateFormat(pattern);
        }

        return formatList.toArray(new SimpleDateFormat[0]);
    }
}

Using the above code, a method on another class could format (or parse) multiple date strings as follows:

public static void printFormatted(String date)
{
    for (SimpleDateFormat sdf:FormatClass.LOCAL_FORMATS.get())
    {
        System.out.println(sdf.format(date));
    }
}

where the printFormatted() method may or may not be static, but will definitely be accessed by multiple different threads.

Will the above approach work as expected?

PNS
  • 19,295
  • 32
  • 96
  • 143
  • 1
    When you use the `toArray` method, it is more efficient to use [`new SimpleDateFormat[list.size()]`](http://stackoverflow.com/questions/174093/toarraynew-myclass0-or-toarraynew-myclassmylist-size). – Jeffrey May 08 '12 at 01:09
  • Nope, if you look at the source code of the toArray() method, it is exactly the same. – PNS May 08 '12 at 01:23
  • 1
    Read the link I gave you. It is not exactly the same, if you provide an array that is initially big enough to contain the entire list, it will use that array. If you do not, it will have to allocate an entirely new array and cast it to the correct type. – Jeffrey May 08 '12 at 01:27
  • See also http://stackoverflow.com/questions/11376328/threadlocal-and-simpledateformat-array, a newer question on the issue, which clarifies that the reference to the SimpleDateFormat[] array should always be obtained via LOCAL_FORMATS.get(), as opposed to initializing once a public variable to LOCAL_FORMATS.get() and then using that variable to reference the array; in the latter case, all threads access the same copy of the array, which is obviously not thread safe. – PNS Jul 07 '12 at 16:30

4 Answers4

3

To answer to your question straightly : yes, every thread will have their own unique copy as recommended in the doc of SimpleDateFormat.

Moinonime
  • 304
  • 1
  • 5
  • 12
  • You mean the code I posted will achieve that, yes? I am aware of the documentation, hence the use of ThreadLocal. – PNS May 08 '12 at 01:24
  • Yes, with this code every thread will be able to use those SimpleDateFormat safely because there will be a unique array of SimpleDateFormat for EVERY thread that asks for it, so be careful if you have a lot of thread. – Moinonime May 08 '12 at 01:40
1

It looks pretty good, but you can easily test it with a multi-threaded program. Just print the Id of the thread (Thread.currentThread().toString()) and System.identifyHashCode(simpleDateFormat) and verify that you are getting unique copies for each thread and appropriately reusing them.

Francis Upton IV
  • 19,322
  • 3
  • 53
  • 57
0

This works well but the code is relatively complex. I would propose to check maybe you can assign the SimpleDateFormat to some local variable inside the method (always thread local). This works well when many values are formatted in a loop that then can be inside the same method.

Audrius Meškauskas
  • 20,936
  • 12
  • 75
  • 93
0

I think there's a more elegant approach that no one has proposed yet -- just create a drop-in replacement wrapper class for SimpleDateFormat that synchronizes access to its methods. In most situations, I would argue that the synchronization overhead is no worse than the hash lookup in ThreadLocalMap.

Andy
  • 7,885
  • 5
  • 55
  • 61