In my Java classes, I sometimes make use of a ThreadLocal
mainly as a means of avoiding unnecessary object creation:
Since the thread was not created by you, it only was rented by you, I think it is fair to require to clean it before stop using - just as you fills up the tank of a rented car when returning. Tomcat could just clean everything itself, but it does you a favor, reminding of forgot things.
ADD:
The way you use prepared GregorianCalendar is simply wrong: since service requests can be concurrent, and there is no synchronization, doCalc
can take getTime
ater setTime
invoked by another request. Introducing synchronization would make things slow, so that creating a new GregorianCalendar
could be a better option.
In other words, your question should be: how to keep pool of prepared GregorianCalendar
instances so that its number is adjusted to request rate. So as a minimum, you need a singleton which contains that pool. Each Ioc container has means to manage a singleton, and most have ready object pool implementations. If you do not yet use an IoC container, start to use one (String, Guice), rather than reinvent the wheel.
Well, a bit late to the party on this one. In October 2007, Josh Bloch (co-author of java.lang.ThreadLocal
along with Doug Lea) wrote:
"The use of thread pools demands extreme care. Sloppy use of thread pools in combination with sloppy use of thread locals can cause unintended object retention, as has been noted in many places."
People were complaining about the bad interaction of ThreadLocal with thread pools even then. But Josh did sanction:
"Per-thread instances for performance. Aaron's SimpleDateFormat example (above) is one example of this pattern."
ThreadLocal
, you have limited options for doing that. Either:
a) you know that the Thread
(s) where you put values will terminate when your application is finished; OR
b) you can later arrange for same thread that invoked ThreadLocal#set() to invoke ThreadLocal#remove() whenever your application terminatesIn short, deciding to use a ThreadLocal as a form of fast, uncontended access to "per thread instance pools" is not a decision to be taken lightly.
NOTE: There are other uses of ThreadLocal other than 'object pools', and these lessons do not apply to those scenarios where the ThreadLocal is only intended to be set on a temporary basis anyway, or where there is genuine per-thread state to keep track of.
Threre are some consequences for library implementors (even where such libraries are simple utility classes in your project).
Either:
java.util.concurrent.ThreadLocalRandom
, it might be appropriate. (Tomcat might still whinge at users of your library, if you aren't implementing in java.*
). It's interesting to note the discipline with which java.*
makes sparing use of the ThreadLocal technique.OR
LibClass.releaseThreadLocalsForThread()
when I am finished with them.Makes your library 'hard to use properly', though.
OR
new ExpensiveObjectFactory<T>() { public T get() {...} }
if you think it is really neccesasry".Not so bad. If the object are really that important and that expensive to create, explicit pooling is probably worthwhile.
OR
servletContext.addThreadCleanupHandler(new Handler() {@Override cleanup() {...}})
It'd be nice to see some standardisation around the last 3 items, in future JavaEE specs.
Actually, instantiation of a GregorianCalendar
is pretty lightweight. It's the unavoidable call to setTime()
which incurs most of the work. It also doesn't hold any significant state between different points of a thread's exeuction. Putting a Calendar
into a ThreadLocal
is unlikely to give you back more than it costs you ... unless profiling definitely shows a hot spot in new GregorianCalendar()
.
new SimpleDateFormat(String)
is expensive by comparison, because it has to parse the format string. Once parsed, the 'state' of the object is significant to later uses by the same thread. It's a better fit. But it might still be 'less expensive' to instantiate a new one, than give your classes extra responsibilities.
If its any help I use a custom SPI (an interface) and the JDK ServiceLoader
. Then all of my various internal libraries (jars) that need to do unloading of threadlocals just follow the ServiceLoader pattern. So if a jar needs threadlocal cleanup it will automatically get picked if it has the appropriate /META-INF/services/interface.name
.
Then I do the unloading in a filter or listener (I had some issues with listeners but I can't recall what).
It would be ideal if the the JDK/JEE came with a standard SPI for clearing threadlocals.
After thinking about this for a year, I've decided it is not acceptable for a JavaEE container to share pooled worker threads between instances of un-related applications. This is not 'enterprise' at all.
If you're really going to share threads around, java.lang.Thread
(in a JavaEE environment, at least) should support methods like setContextState(int key)
and forgetContextState(int key)
(mirroring setClasLoaderContext()
), which permit the container to isolate application-specific ThreadLocal state, as it hands the thread between various applications.
Pending such modifications in the java.lang
namespace, it is only sensible for application deployers to adopt a 'one thread-pool, one instance of related applications' rule, and for application developers to assume that 'this thread is mine until ThreadDeath us do part'.
I think JDK's ThreadPoolExecutor could do ThreadLocals cleaning after task execution but as we know it doesn't. I think it could have provided at least an option. The reason why might be because Thread provides only package private access to its TreadLocal maps, so ThreadPoolExecutor just cannot access them without changing Thread's API.
Interestingly, ThreadPoolExecutor has protected method stubs beforeExecution
and afterExecution
, API says: These can be used to manipulate the execution environment; for example, reinitializing ThreadLocals...
. So I can imagine a Task that implements a ThreadLocalCleaner interface and our custom ThreadPoolExecutor that on afterExecution calls task's cleanThreadLocals();