We know that the dateformat classes are not thread safe. I have a multi-threaded scenario where dateformats needs to be used. I can't really create a new instance in new thread as SimpledateFormat creation seems to be expensive(the constructor ends up calling "compile" which is costly). After some tests the only two options left for me are:
- External Synchronization - I really dont want to do this
- Cloning in each thread - Don't know whether there are some catches?
Any suggestions?
If guys have faced this before, what direction did you take.
Note: a similar question was asked before, but it was closed pointing to a apache package. I can't use new libraries for this. And I have also read this similar question on SO
We've switched to using thread-safe FastDateFormat
I have used the ThreadLocal to store an instance of each date format i use.
I would have a small cache of SimpleDateFormats you can lock on. Each lock will cost you 1-2 micro seconds, but you might want to see how long creating a new object each time costs you.
Since ThreadLocal is not possible in your case, you should use a pool. Get or create a new instance, use it, and put it in the pool afterwards.
What if you created a class which would format dates using a fixed size pool of precreated SimpleDateFormat objects in round-robin fashion? Given that uncontested synchronization is cheap, this could synchronize on the SimpleDateFormat object, amortizing collisions across the total set.
So there might be 50 formatters, each used in turn - collision, and therefore lock contention, would occur only if 51 dates were actually formatted simultaneously.
EDIT 2011-02-19 (PST)
I implemented a fixed pool as suggested above, the code for which (including the test), is available on my website.
Following are the results on a Quad Core AMD Phenom II 965 BE, running in the Java 6 SE client JVM:
Notably, cloning and pooling were very close together. In repeated runs, cloning was faster than pooling about as often as it was slower. The test, of course, was deliberately designed for extreme contention.
In the specific case of the SimpleDateFormat, I think I might be tempted to just create a template and clone it on demand. In the more general case, I might be tempted to use this pool for such things.
Before making a final decision one way or the other, I would want to thoroughly test on a variety of JVMs, versions and for a variety of these kinds of objects. Older JVMs, and those on small devices like handhelds and phones might have much more overhead in object creation and garbage collection. Conversely, they might have more overhead in uncontested synchronization.
FWIW, from my review of the code, it seemed that SimpleDateFormat would most likely have the most work to do in being cloned.
EDIT 2011-02-19 (PST)
Also interesting are the uncontended single-threaded results. In this case the pool performs on par with a single synchronized object. This would imply that the pool is the best alternative overall, since it delivers excellent performance when contented and when uncontended. A little surprising is that cloning is less good when single threaded.
Must point out that option 2: "Cloning in each thread - Don't know whether there are some catches?" is only a viable option because SimpleDateFormat and DateFormat implement a deep clone(). A shallow clone would not be any more thread-safe than just using the same instance.
The reason DateFormat and any subclasses are not thread-safe is due to DateFormat using an internal instance of Calendar stored as a member variable. Calls to format() or parse() rely on clear(), set() and get() fields on the Calendar instance. Any concurrent calls are likely to corrupt the internal Calendar state.
It is also the fact that the classes implement a deep clone() that makes it relatively slow.