Monday, July 21, 2008

Help Me ThreadLocal Variables!

I attended a local NoFluffJustStuff seminar last weekend and enjoyed every discussion I attended. Ted Neward was in excellent form as usual. There was one thing that bothered me though. There were quite a few attendees that did not know how to utilize ThreadLocal variables and some had never heard of them.
I'll discuss and demonstrate them here and in the next post I'll demo using hibernate Sessions with ThreadLocal variables. Hopefully, this will help out a lot of people.
ThreadLocal variables are instances of the java.lang.ThreadLocal<T> class. There are two methods (it has more) that we are concerned with get() and set(T value) which perform the normal accessor and mutator functionality. Here's the main point! These variables differ from the variables you are used to in that each thread that accesses a ThreadLocal variable via its get or set method has its own, independently initialized copy of the variable. That's where the class' name came from, the variable is local to the Thread that has it.
Each thread holds an implicit reference to its copy of a thread-local variable as long as the thread is alive and the ThreadLocal instance is accessible. When a Thread dies all of its ThreadLocal variables are garbage collected if there are no references to them.
This gives you what I call poor man's thread safety. Other threads won't bother it and it won't bother other threads. So how can I utilize these variables? It's actually quite simple. Here's the example I promised.

Class UserHelper {
private static final ThreadLocal threadUser = new ThreadLocal();

/** Retrieves the user name of this thread. */
public static String getThreadUser() {
return threadUser.get();
}

/** Stores the user name of this thread. */
public static void setThreadUser(String username) {
threadUser.set(username);
}
}

This class stores the current user's name in a threadlocal variable attached to the current thread of execution and the Thread lugs it around wherever it goes. In any part of the application this user name can be accessed by simply calling the getThreadUser() method. Even though you may have two different threads executing the same part of an application, when the application calls the get method each thread returns it's own user's name. Simple huh?

Warning
Always remember that the ThreadLocal data is connected to the thread, not the user (in our example it has the user name but that's it) or anything else. A good idea is to delete the ThreadLocal data when it's no longer used.
MyThreadLocal.set(null);

We'll talk about the Hibernate ThreadLocal Session pattern in the next installment.