推荐Java Code Geeks上的两篇文章：
When and how to use a ThreadLocal
Instead of grinding my teeth, I decided to open up the topic by publishing two articles, first of which you are currently reading. In the post I explain the motivation behind ThreadLocal usage. In the second post currently in progress I will open up the ThreadLocal bonnet and look at the implementation.
Let us start with an imaginary scenario in which ThreadLocal usage is indeed reasonable. For this, say hello to our hypothetical developer, named Tim. Tim is developing a webapp, in which there is a lot of localized content. For example a user from California would expect to be greeted with date formatted using a familiar MM/dd/yy pattern, one from Estonia on the other hand would like to see a date formatted according to dd.MM.yyyy. So Tim starts writing code like this:
After a while, Tim finds this to be boring and against good practices – the application code is polluted with such initializations. So he makes a seemingly reasonable move by extracting the DateFormat to an instance variable. After making the move, his code now looks like the following:
Happy with the refactoring results, Tim tosses an imaginary high five to himself, pushes the change to the repository and walks home. Few days later the users start complaining – some of them seem to get completely garbled strings instead of the former nicely formatted dates.
Investigating the issue Tim discovers that the DateFormat implementation is not thread safe. Meaning that in the scenario above, if two threads simultaneously use the formatCurrentDate() and formatFirstOfJanyary1970() methods, there is a chance that the state gets mangled and displayed result could be messed up.
So Tim fixes the issue by limiting the access to the methods to make sure one thread at a time is entering at the formatting functionality. Now his code looks like the following:
Reading further about the issue Tim discovers a different type of variables called ThreadLocal. These variables differ from their normal counterparts in that each thread that accesses one (via ThreadLocal’s get or set method) has its own, independently initialized copy of the variable. Happy with the newly discovered concept, Tim once again rewrites the code:
Going through a process like this, Tim has through painful lessons learned a powerful concept. Applied like in the last example, the result serves as a good example about the benefits.
But the newly-found concept is a dangerous one. If Tim had used one of the application classes instead of the JDK bundled DateFormat classes loaded by the bootstrap classloader, we are already in the danger zone. Just forgetting to remove it after the task at hand is completed, a copy of that Object will remain with the Thread, which tends to belong to a thread pool. Since lifespan of the pooled Thread surpasses that of the application, it will prevent the object and thus a ClassLoader being responsible for loading the application from being garbage collected. And we have created a leak, which has a chance to surface in a good old java.lang.OutOfMemoryError: PermGen space form
Another way to start abusing the concept is via using the ThreadLocal as a hack for getting a global context within your application. Going down this rabbit hole is a sure way to mangle your application code with all kind of unimaginary dependencies coupling your whole code base into an unmaintainable mess.
Threading stories: ThreadLocal in web applications
ThreadLocalvariables in our web applications. The reason was that they created classloader leaks and we coudn’t undeploy our applications properly anymore.
Classloader leaks happen when a GC root keeps referencing an application object after the application was undeployed. If an application object is still referenced after undeploy, then the whole class loader can’t be garbage collected cause the considered object references your applications class file which in turn references the classloader. This will cause an OutOfMemoryError after you’ve undeployed and redeployed a couple of times.
——如果在应用被undeployed之后，GC root还保持着某个应用对象的引用；→ 则整个classloader都不会被垃圾回收；→ 则会导致ClassLoader Leak。导致OutOfMemoryError
ThreadLocal is one classic candidate that can easily create classloader leaks in web applications. The server is managing its threads in a pool. These threads live longer than your web application. In fact they don’t die at all until the underlying
JVM dies. Now, if you put a
ThreadLocal in a pooled thread that references an object of your class you *must* be careful. You need to make sure that this variable is removed again using
The issue in web applications is: where is the right place to safely remove
ThreadLocal variables? Also, you may not want to modify that “removing code” every time a colleague decided to add another
ThreadLocal to the managed threads.
We’ve developed a wrapper class around thread local that keeps all the thread local variables in one single
ThreadLocal variable. Here is the code.
The advantage of the utility class is that no developer needs to manage the thread local variable lifecycle individually. The class puts all the thread locals in one map of variables.
destroy() method can be invoked where you can safely remove all thread locals in your web application. In our case thats a
ServletRequestListener -> requestDestroyed() method. You will also need to place finally blocks elsewhere. Typical places are near the
HttpServlet, in the
doGet() methods. This may remove all thread locals in the pooled worker threads after the request is done or an exception is thrown unexpectedly. Sometimes it happens that the
main thread of the server leaks thread local variables. If that is the case you need to find the right places where to call the
ThreadLocalUtil -> destroy() method. To do that figure out where the main thread actually *creates* the thread variables. You could use your debugger to do that.
Many guys out there suggest to ommit
ThreadLocal in web applications for several reasons. It can be very difficult to remove them in a pooled thread environment so that you can undeploy the applications safely.
ThreadLocal variables can be useful, but it’s fair to consider other techniques before applying them. An alternative for web applications to carry request scope parameters is the
HttpServletRequest. Many web frameworks allow for generic request parameter access as well as request/session attribute access, without ties to the native Servlet/Portlet API. Also many framework support request scoped beans to be injected into
an object tree using dependency injection. All these options fulfill most requirements and should be considered prior to using