How to shoot yourself in foot with ThreadLocals

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.
 
 
Shoot
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:

 

Reference: How to shoot yourself in foot with ThreadLocals from our JCG partner Nikita Salnikov Tarnovski at the Plumbr Blog blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


three × 2 =



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close