In my Java classes, I sometimes make use of a ThreadLocal
mainly as a means of avoiding unnecessary object creation:
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() { 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.