Beyond thread confinement: InheritableThreadLocals
After some time, I'm writing again. Hope I do not stay so long without posting again.
The ThreadLocal class allow you to set values that are accessible from the thread that stored such value. Using a thread local you can set the value and as long as you are in the same thread and have access to the thread local instance you can retrieve such value. Value is retrievable only from that thread and can be a good option to confine values to the thread which can be accessible from any method without having to be passed as a parameter.
To illustrate this behavior, we can see the following piece of code:
package threadLocal;
public class ThreadLocalTest {
public static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<String>();
public static void main(String[] args) {
THREAD_LOCAL.set("Any value...");
MyClass obj = new MyClass();
obj.execute();
}
}
package threadLocal;
public class MyClass {
public void execute() {
String value = ThreadLocalTest.THREAD_LOCAL.get();
System.out.println(value);
}
}
In the code shown, the class ThreadLocalTest has a static property which is a thread local instance called THREAD_LOCAL. This static property is capable of maintaining values associated to the thread. When MyClass.execute() method is invoked it prints the value put by the main method even tough it had no parameter and the value was put by the main method. As long as they are in the same thread, it prints "Any value...".
If we change the code to something like we see bellow (omitting MyClass already shown):
package threadLocal;
public class ThreadLocalTest {
public static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<String>();
public static void main(String[] args) {
THREAD_LOCAL.set("Any value...");
Thread otherThread = new Thread() {
@Override
public void run() {
MyClass obj = new MyClass();
obj.execute();
}
};
otherThread.start();
}
}
Now the execution prints null. This is because the value was put by the Main thread (yes, the main runs in its own thread) and we try to read it from a different one, represented by the otherThread object we created.
A nice thing beyond simple thread locals, that we have just shown, is that you can use the InheritableThreadLocal class. This class allow a thread and any threads started by it (and so on down the chain) to have access to the values put by threads higher up in the chain.
Let's see an example. Change the class ThreadLocalTest to something like what is shown bellow:
package threadLocal;
public class ThreadLocalTest {
public static final InheritableThreadLocal<String> THREAD_LOCAL = new InheritableThreadLocal<String>();
public static void main(String[] args) {
THREAD_LOCAL.set("Any value...");
Thread otherThread = new Thread() {
@Override
public void run() {
MyClass obj = new MyClass();
obj.execute();
}
};
otherThread.start();
}
}
Now, running this test prints Any value... again. This is due to the fact that the otherThread is started by the main thread, so it inherits the thread local attributes associated with the starter thread.
ThreadLocal and the InheritableThreadLocal are great features. Just take some precautions like guaranteeing that you remove the values associated with the threads via ThreadLocal.remove()method, specially in environments where the threads are pooled and reused.