How to shoot yourself in foot with ThreadLocals

January 22, 2013 by Nikita Salnikov-Tarnovski

It will start nicely. Like most of the stories. You discover a new concept and are amazed by it’s powers. And then equipped with this new hammer suddenly everything starts to look like a nail. From what we have experienced in past months, java.lang.ThreadLocal makes one hell of a hammer.

I guess it all boils down to the very concept of how ThreadLocal works. It’s easiest to grasp the concept via the scoping analogy. In the very same way your Spring beans can be for example container, session or request scoped. ThreadLocal equips you with the possibility to declare objects in Thread scope.

You can set any object to ThreadLocal and this object will have both global and local scope in the thread accessing this object. It might be complex to grasp at first but let me explain:

  • Values stored in ThreadLocal are globally accessible to the thread. Meaning that if you have access to ThreadLocal reference within your code, then the values stored in it can be accessed from anywhere inside that thread. If a thread calls methods from several classes, then all the methods can see the ThreadLocal variable set by other methods (because they are executing in same thread). The value need not be passed explicitly. It’s like how you would use global variables.
  • Values stored in ThreadLocal are local to the thread, meaning that each thread will have it’s own ThreadLocal variable. A thread cannot access/modify other thread’s ThreadLocal variables.

So here we have a reason to celebrate – we have a truly powerful concept in our hands. It is often the easiest way to render a stateful class thread-safe. And encapsulate non-thread-safe classes so that they can safely be used in multithreaded environments. In addition to simplicity, using ThreadLocal to store a per-thread-singleton or per-thread context information has a valuable information included – by using a ThreadLocal, it’s clear that the object stored in the ThreadLocal is not shared between threads, simplifying the task of determining whether a class is thread-safe or not. Which we have found is not an easy task when you have a codebase of 1,000,000 lines at hand.

On the other hand, this powerful concept creates numerous problems in wrong hands. Like any other abused design concept. In the past months we have most often faced two problems:

  • ThreadLocal gives you the opportunity to use the variables without explicitly passing them down through the method invocation chain. Which could be useful on certain occasions. But you guys out there who have created a n-layer architecture to abstract away different communication interfaces. And then grab HttpServletRequest from ThreadLocals in your DAO objects … what were you smoking when making this decision? It took a few hours and a second pair of eyes when we were digging up this particular case. But anyhow – be careful when using the powers of globalization. You end up creating unexpected dependencies within your code. And as you might remember – this is not a wise thing to do.
  • It is darn easy to introduce a memory leak to your code when using a ThreadLocal. Which serves as a nice demonstration about the complexities surrounding classloaders. If you are deploying your code in an application server then your application classes are loaded/unloaded with a different classloader than the one used by the application server itself.  Which is not bad per se. But now considering that modern application servers also pool threads instead of creating a new one on each HttpRequest, we have built the foundation to a problem.

If one of the application classes stores a value in ThreadLocal variable and doesn’t remove it after the task at hand is completed, a copy of that Object will remain with the Thread (from the application server 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.

So should we avoid using ThreadLocal considering the harm it can cause? Maybe not so fast Joshua Bloch has said half a decade ago:

“Can you cause unintended object retention with thread locals? Sure you can. But you can do this with arrays too. That doesn’t mean that thread locals (or arrays) are bad things. Merely that you have to use them with some care. 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. But placing the blame on thread locals is unwarranted.”

I tend to agree to Mr. Bloch and do not think ThreadLocal is an evil creation. But I also do think it is a concept which many fail to understand properly.

Inspiration for this article was mainly gathered during sleepless hours of tracing down some nasty bugs. But while writing, following resources proved to be beneficial as well:

  • Veera Sundar blogpost explaining scoping
  • Javin Paul summary about ThreadLocal leaks

If you enjoyed the post then – stay tuned for more. We continue to publish on interesting Java – related content on a weekly basis.

Can't figure out what causes your OutOfMemoryError? Read more

ADD COMMENT

COMMENTS

Woah, what freakin’ cool picture! Who would think the dudes are discussing ThreadLocal here…so cool.

Marcel Stör

Thanks, I pass your feelings to our marketing guys :)

iNikem

ThreadLocals are variables after all, so the guidelines for accessing them are the same ones as for instance or static variables.nThat leaves the possible memory-leak as the only ThreadLocal-specific problem.nn

Frisian

ThreadLocals are variables that seems to be somewhat different from any other variable. I haven’t seen a globally accessible instance variable for quite some time. And when using static global fields developers at least vaguely aware that they should care about thread safety and, sometimes, resource cleanup. ThreadLocals are often seen as an indulgence of some kind. But sure that is not ThreadLocal-only problem.

iNikem

They aren’t “globally accessible instance variables”. As Frisian said, they’re just like normal static variables, so the guidelines for accessing them are the same ones as for instance or static variables.nnExcept that they contain a different instantiation per thread, thereby risking them not to be cleaned up when using thread pools. But other than that, they’re not some “magic” global variable: you only access them as you access normal static variables. There’s nothing “global” about then, you still have to pass around the ThreadLocal reference – certainly if it’s some private class member.

local

Can't figure out what causes your OutOfMemoryError? Read more

Latest
Recommended
You cannot predict the way you die
When debugging a situation where systems are failing due to the lack of resources, you can no longer count on anything. Seemingly unrelated changes can trigger completely different messages and control flows within the JVM. Read more
Tuning GC - it does not have to be that hard
Solving GC pauses is a complex task. If you do not believe our words, check out the recent LinkedIn experience in garbage collection optimization. It is a complex and tedious task, so we are glad to report we have a whole lot simpler solution in mind Read more
Building a nirvana
We have invested a lot into our continuous integration / delivery infrastructure. As of now we can say that the Jenkins-orchestrated gang consisting of Ansible, Vagrant, Gradle, LiveRebel and TestNG is something an engineer can call a nirvana. Read more
Creative way to handle OutOfMemoryError
Wish to spend a day troubleshooting? Or make enemies among sysops? Registering pkill java to OutOfMemoryError events is one darn good way to achieve those goals. Read more