tl;dr ThreadLocal or ‘beautiful architecture’. Pick one.
Now. Don’t get me wrong. I’m rewriting this article for around the third time, and my opinion has softened on each attempt. To rebut my original tl;dr:
ThreadLocal certainly isn’t anywhere near as bad as
Singleton! They lack
Singleton‘s most glaring evil – the global access. Someone needs to hand you the right
ThreadLocal<T> in order for you to get the
T out; you can’t just do
ThreadLocal::get and magically have the thing you want.
That’s not to say that
ThreadLocal is good, however. In most systems one would argue that an opportunity to express the threading model of your application in the object model has been lost. Let the code speak, and let it speak in the tongues of a dependency graph of objects that is well formed (or at least acyclic)!
To aid you in your quest of object/threading model sympathy, herefollows a critiqued example of potential
It’s that canonical java problem! SimpleDateFormat is not thread safe.
Imagine the scene. We’re in a java web server, and thousands of clients are trying to access pages and pages of content that urgently need some dates to be formatted. Unfortunately, some poor soul missed the relevant javadoc that explains the not thread safeness of
SimpleDateFormat, and some of those web pages are coming out with dates in 1970.
The horror. We could very easily solve this with a
ThreadLocal<SimpleDateFormat> and arrange for our servlets to have access to it. At the point where we need to format a date in servlet code we just grab the formatter out of the ThreadLocal and use it. Frankly, that’s not the worst thing we could do here. Date formatting is unlikely to be the raison d’etre of your program, so promoting it to a first class threading concern could be overkill.
A little deeper
Let’s imagine we really care about this though (not too tricky for me, your mileage may vary).
We could use JodaTime instead (or the new spingly new Date/Time stuff coming in java 8). For this particular problem this is probably the most sensible option. If we think about the contract of
format, it really shouldn’t need a shared resource in order to function. It came as no surprise to me that a static instance of
DateTimeFormatter performed roughly the same as a
ThreadLocal<SimpleDateFormat> in the tests we ran that last time I was near this particular argument.
The vacuity of our example is, sadly, getting in the way of a more serious discussion. Let’s once again call upon our (now collective) imagination and enter a world in which we really do care about minimizing the resource usage of a call to format, or, at least, putting a constant limit on it.
A little deeper still
SDF) uses a buffer to build up the eventually returned
String date, and it is the usage of this buffer that is at the heart of the lack of thread safety. We at least know that we have one buffer per instance of
SDF though, and one guesses that we have one buffer per invocation of
format in the JodaTime equivalents. Perhaps we see that we’re spending most of our GC time on these objects and wish to ameliorate affairs (although how these objects are escaping young gen to cause such problems seems odd).
Once again, we can very easily solve this by using a
ThreadLocal<SDF> member in the class that needs it. But this isn’t the right thing to do. We’re introducing a synchronization (really? -Ed) mechanism at the base of our program. In general it is reasonable to be suspicious of
newing business objects (other than temporaries or state) at runtime, particularly at the bottom of the stack.
Imagine you’re a thread executing this particular servlet; let’s say in response to a get request for some user details. The thread walks (I imagine the thread as a spider, here) across a series of data structures, picking out the pieces of data it requires, and then attempts to format the data according to some presentation code, and bzzt secretly accesses just the right formatter to do it.
Why is this bad?
unit < library < thread < application (the precise definition of what ‘<‘ means is left as an exercise to the reader)
Hopefully the buzzer going off points to where my discomfort comes from. Full marks if you recognised that it’s pulling out the
SDF from the hat of the current thread’s context. Units, libraries – whatever term you prefer – ideally should not know too much about the context in which they execute. Having threading related knowledge in the wrong context is going to make your application hard to parse, but for the runtime and other programmers in the nearby.
Instead, we should push formatter construction up into the ‘thread’ area of our application’s wiring. That way the code below there stops knowing about its execution context, and we’re a little closer to our ideal ‘nested’ architecture, where our libraries are happy little islands that just know about other library interfaces and very little about threads.
This feels more maintainable than the
ThreadLocal solution; consider what happens when a second
ThreadLocal in a different servlet is required (yes, we could pass the
ThreadLocal around, but if you’re going to do that work, why not do it properly?). In the more explicit approach, we just pass the formatter around a bit more, or if it’s a different class, our Thread object has another field, and all of our non-thread-safe components can be found in a single place by those who are unfortunate enough to follow us.
I’ve stretched this example to its limit; I’d probably have opted for the Joda option. If you’ve made it this far, I congratulate you on your powers of imagination.
Oh, and, as ever, having written this, I find someone’s already written it better, years ago. Here’s Bob Martin espousing on
ThreadLocal in a similar vain.