ThreadLocal: Not My Cup Of Tea
Or perhaps ThreadLocal<NotMyCupOfTea>
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 ThreadLocal
usage.
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
SimpleDateFormat
( 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 new
ing 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.
Apologies
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.