ThreadLocal is one of the lesser known, and seldom used Core Java objects. Its purpose is to bind an object to a thread, which has two distinct and useful consequences: The object is not shared between threads, so it can be used without the need for synchronization; and it is available throughout the life of the thread, meaning you don’t have to pass it all over the place through method calls. ThreadLocal has advantages in common with both local variables and global variables. While it is powerful, it also has some drawbacks, so in this article, I show you how and when to use it.

When you learned Java, you may have come across ThreadLocal. Very likely, you didn’t see how it could ever be useful, and why you should care. Sure, it might be handy when doing multi-thread programming, but for day-to-day coding? Nah.

But as it turns out, if you’re working on a Web application in Java, you are working in a multi-threaded environment. While you can ignore that fact most of the time, some times it is essential to understand how the threads interact. Otherwise, you may encounter some of the hardest bugs to find and fix: those caused by thread interference and called “race conditions.” They are intermittent, difficult to reproduce, and really hard to get under the microscope that is your debugger. The best approach is to guard against them from the start by erecting walls between your threads where they are needed.

Thread safety

Anytime you write a Java application, you are working in a multi-threaded environment. Each time a client makes a request, the application server (whether it’s Apache’s Tomcat, JBoss, Jetty, or any other) allocates a thread to respond to that client. In most cases, the application server uses a thread pool. As the name implies, the threads are pooled: the application server creates some threads when it starts, and doles them out to handle the incoming requests as needed. When the request is fulfilled, the thread is returned to the pool until it is needed again. Each pool manager has different ways of handling the details, but this description should be sufficient for now.

When writing your application, ask yourself, “What happens if I get two requests at the same time?” If two threads execute the same method at the same time, and the methods do not modify shared data – that is, if they only use variables declared in the method itself or objects referenced inside the method – you’re safe. If you’re dealing with a larger application in which you need to access various service objects and interface with a persistence layer, then you have to be more careful.

Let’s say we have a service that calculates the monthly payments on a loan based on the principal, annual interest rate, and length of the loan. For argument’s sake, I’m coding it in a way I know is not thread safe, to show how the problem might occur:

public class InterestService {

private static InterestService instance;

public static synchronized InterestService getInstance() {

if (instance == null) {

instance = new InterestService();

}

return instance;

}

int principal;

int annualRate;

int years;

public void setYears(int years) {

this.years = years;

}

public void setAnnualRate(int annualRate) {

this.annualRate = annualRate;

}

public void setPrincipal(int principal) {

this.principal = principal;

}

public double calculate() {

double p = principal/ 100.0;

double j = annualRate / 1200.0;

double n = years * 12.0;

// M = P * ( J / (1 - (1 + J) ** -N))

return p * (j / (1 - Math.pow(1+j, -n)));

}

}

We can use it either from a JSP or as part of more elaborate code:

InterestService service = InterestService.getInstance();

String results = "";

try {

service.setPrincipal(Integer.valueOf(request.getParameter("principal")));

service.setAnnualRate(Integer.valueOf(request.getParameter("annualRate")));

service.setYears(Integer.valueOf(request.getParameter("years")));

results = String.valueOf(service.calculate());

} catch (NumberFormatException e) {

e.printStackTrace();

}

The code is simple enough: You set the parameters one by one, then you fetch the result. Nothing can go wrong… as long as only one person uses your system at one time. If two people ask for the correct repayment installments on a loan at the same time, the parameters could get mixed, and one or both of the users would get the wrong results.

One typical way to solve this problem is to use a brand new InterestService each time we need to calculate the interest, and in most cases, that is indeed the correct answer. However, sometimes creating a new instance of a class (service or otherwise) is costly, and we may want to reuse the ones we create as much as possible.

Taking our example further, we could have a method that formats a loan description. This method, in turn, is called multiple times with various parameters so the user gets a better idea of her options:

public String formatLoan(int principal, int annualRate, int years) {

InterestService service = new InterestService();

service.setPrincipal(principal);

service.setAnnualRate(annualRate);

service.setYears(years);

double res = service.calculate();

MessageFormat msg =

new MessageFormat("A loan for {0,number,$0.00} " +

"at a rate of {1}% per year " +

"for {2} years would cost you " +

"{3,number,$0.00} per month");

Object [] args = {

Integer.valueOf(principal),

Integer.valueOf(annualRate),

Integer.valueOf(years),

Double.valueOf(res)};

return msg.format(args);

}

and

ArrayList results = new ArrayList();

for (int y = 1; y < 10; y++ ) {

results.add(formatLoan(principal, annualRate, y));

}

With this code, we’re creating several instances of the InterestService, when we don’t really have to. We just need one that no other thread will touch. We could create it in the caller, and pass it to formatLoan(), but that’s getting a bit cumbersome. What if the caller, in turn, is called repeatedly from another part of the code? Should it also take the InterestService as a parameter? It’s getting ridiculous!

We solve this problem with a ThreadLocal in InterestService:

private static ThreadLocal<InterestService> instance;

public static synchronized InterestService getInstance() {

return instance.get();

}

And when we need an InterestService, we use

InterestService service = InterestService.getInstance();

You can think of the ThreadLocal as a coat check clerk, and your code as the patron who wants his coat back. The thread is the claim ticket. A patron can only get a coat he previously left with the clerk, and similarly, our code can only get back an object it has previously left with the ThreadLocal. There are two ways to get the object into the ThreadLocal: We can set it using the set() method, or we can have the ThreadLocal create it for us by overriding ThreadLocal’s initialValue() method. It looks like this:

private static ThreadLocal<InterestService> instance = new ThreadLocal() {

@Override

protected InterestService initialValue() {

return new InterestService();

}

};

In this example, all the threads want to initialize their object in the same way, so the initialValue() is the better approach. In other situations, you don’t know ahead of time what the value should be, so that’s when to use set().

Are you using thread-safe libraries?

You may find my example of InterestService a bit convoluted. After all, who sets parameters and uses a different method to fetch the results? It happens more than you’d think. If you’re using Java Beans and PropertyEditors, that is exactly how property editors work. You call setAsText() then getValue() or setValue() and getAsText(). As a general rule, do not consider property editors thread-safe.

Another group of classes is also not thread-safe, and they have caught a few developers by surprise: the java.text Formats: MessageFormat, NumberFormat, DateFormat… You should always be careful how you use them. If it is possible for multiple threads to access these at the same time, you should wrap them in a ThreadLocal, or otherwise synchronize access.

To wrap a Format, or any other non-thread-safe object in a ThreadLocal, you need a variable for the ThreadLocal that is easily access by your code. In most situations that’s in a static field, but if your code is in a singleton object, there’s no reason it can’t be an attribute of your object. Make sure that your code can get to it anytime it needs it. Just as we did above, you can override initalValue() or use set() to place the non-thread-safe object in the ThreadLocal.

You may even want to create a static class for the sole purpose of holding on to the ThreadLocal that has your non-thread-safe object. Let’s say you’re working with a library that provides a Point class and a PointEditor:

public class Point {

int x;

int y;

public Point(int x, int y) {

this.x = x;

this.y = y;

}

//...

}

public class PointEditor extends PropertyEditorSupport {

public String getAsText() {

Point p = (Point) getValue();

return "(" + p.x + ", " + p.y + ")";

}

//...

}

You write a PointEditorHolder:

public class PointEditorHolder {

protected static ThreadLocal<PointEditor> holder = new ThreadLocal() {

public PointEditor initialValue() {

return new PointEditor();

}

};

public static PointEditor getEditor() {

return holder.get();

}

}

And that’s it. Anywhere in your code where you want to convert a point, ask the PointEditorHolder for an editor, and you know your threads will not tangle. Just to be sure, you confirm with a test:

public class PointEditorHolderTest {

@Test

public void testValue() {

PointEditor pe = PointEditorHolder.getEditor();

assertNotNull(pe);

assert(pe.getClass().equals(PointEditor.class));

}

@Test

public void testNotTheSame() throws InterruptedException {

class Holder {

PointEditor fromT1;

PointEditor fromT2;

}

final Holder holder = new Holder();

Thread t1 = new Thread() {

public void run() {

holder.fromT1 = PointEditorHolder.getEditor();

}

};

Thread t2 = new Thread() {

public void run() {

holder.fromT2 = PointEditorHolder.getEditor();

}

};

t1.start();

t1.join();

t2.start();

t2.join();

assertNotSame(holder.fromT1, holder.fromT2);

}

}

Global-ish values

But, you may think to yourself, “If I can access a value specific to my thread from anywhere at all in my code, doesn’t that mean that I don’t have to pass variables all over from all over?”

YES! A most emphatic YES!

This is one of the side effects of having this ThreadLocal object, and it’s a very good reason on its own to use the class. In a setting such as a Web application, you may have filters that can recognize particular aspects of the request that you want to use later in the code in unrelated contexts. You can use it to keep track of the authentication of the current user; of localization options such as language or date formatting; or site theme preferences. You can use the request object to hold each of these, of course, but then you need to pass the request object all over the code. With a ThreadLocal, you only these when you need them.

I think of these as global-ish values. They’re not really global, but they are just as easy to access. It’s almost like standing in the middle of the dance floor yelling for someone to bring you your coat. But with much better results.

Downsides

Given these marvelous objects, why aren’t we using them all over the place all the time?

Multithreaded programming is not easy, even with ThreadLocals. You must understand the implications of using them. The main issue is that of memory usage. When you initialize an object through the initialValue() method, it’s easy to forget you created it. If it, in turn, creates other objects, all of those stick around for the lifetime of the Thread. They do not become candidates for garbage collection until the thread is all done, and even then, only if no other object is holding on to them. If your code is running in an application server that uses a thread pool, you have no way of knowing when that thread finishes.

Even more dangerous is that if you’re running in a context with a thread pool, the threads are not cleaned up between uses. If you’re using a ThreadLocal to keep track of the currently authenticated user, when you’re done processing the request, the user is still associated with that thread. If the next request for that thread doesn’t associate another user with the thread, the code executes as if the request came from the first user.

If you use a filter to detect some parameters about the request and use it to guide the code being executed for the request, make sure, absolutely sure that you unset (ThreadLocal.set(null)) when you’re done with the request.

If you mind your memory usage, and you clean up after your threads, you should be able to use ThreadLocals safely. They are powerful, practical, and can make programming in a multi-threaded environment a little easier.

See also: