Tuesday, March 16, 2010

ThreadLocal - What's it for

ThreadLocal provides a mechanism of storing objects for the current execution of thread. What this means is that you can stick in a object into a ThreadLocal and expect it to be available at any point during the the executing thread. This comes in handy when you have to make some object made available between different layers (i.e. presentation->business->data access) without making them part of the api. For example implementing cross cutting concerns such as security, transactions make use of the ThreadLocal to access transactional, security contexts between layers, without cluttering the application APIs with non-application specific details.


What happens in the ThreadLocal
ThreadLocal holds a custom hash map that holds objects as values and the current thread as the key. This custom map (ThreadLocalMap) is local to the ThreadLocal and is not exposed as part of the API. So it's basically a HashMap carried through the current thread of execution. That's all to it in a nut-shell as to what goes inside the ThreadLocal.


How to make use of a ThreadLocal
A ThreadLocal is generally used through a custom implementation which holds the ThreadLocal. The custom implementation should have a static field of the type ThreadLocal and would generally expose static accessors to store and retrieve objects to and from the ThreadLocal.
Assume you want to store a FooContext object in the ThreadLocal as part of your application.
Following is an example of a basic implementation to use the ThreadLocal;

public class ThreadLocalHolder {

    private static ThreadLocal store = new ThreadLocal();

    public static void set(FooContext context) {
        store.set(context);
    }

    public static FooContext get() {
        store.get();
    }
}

To see how this is used consider a Business layer object called FooBusinessObject and a DAO callled BarDao. You want some method in the business object to initialise a FooContext, do some work and call the DAO. You then want to be able to access the FooContext you created without making part of the API of the DAO. 

public class FooBusinessObject {

    private BarDao barDao;

    public void doFoo() {
        // Some logic that builds a FooContext
        FooContext context = new FooContext();

        // sticks the context into the ThreadLocal.
        ThreadLocalHolder.set(context); 

        // Do more work....
        barDao.processBar();
    }
}

public class BarDao {

    public void processBar() {
        // Get the context from the thread-local
        FooContext context = ThreadLocalHolder.get();

        // do some work...
    }
}  

That's all that's needed to be able to store and retrieve objects in the ThreadLocal. ThreadLocal is used in many frameworks and is a popular choice for use cases of sharing cross cutting objects during the execution of a thread. 


Is there any danger involved?
There are potential dangers that you could face by using ThreadLocals though. However these dangers are not because of merely using the ThreadLocal, but because its not used properly (as with many other things as well). The issues are apparent when we work on a managed environment, such as a application server that maintains a thread pool dishing out threads for incoming requests. This means one request would get hold of a thread, finish the work involved and then the application server reclaims the thread back to the pool. Now if you stuck an object in the ThreadLocal, it doesn't get removed when the thread returns to the pool unless this is cleaned out. So you've now mixed the state of a thread that finished into another executing thread. 
So as part of using this properly, the thread local needs to be cleared out before the execution ends. This is ideally done in a finally block where the ThreadLocal is nullified. 
The above addition to the ThreadLocalHolder exposes a clear method that cleans out the ThreadLocal for this thread.

public class ThreadLocalHolder {

    private static ThreadLocal store = new ThreadLocal();

    public static void set(FooContext context) {
        store.set(context);
    }

    public static FooContext get() {
        store.get();
    }

    public static void clear() {
        store.set(null);
    }
}
And this is cleared as follows;

public class FooBusinessObject {

    private BarDao barDao;

    public void doFoo() {
        try {
            // Some logic that builds a FooContext
            FooContext context = new FooContext();

            // sticks the context into the ThreadLocal.
            ThreadLocalHolder.set(context);            

            // Do more work....
            barDao.processBar();
        }
        finally {
            // clean up
            ThreadLocalHolder.clear();
        }
    }
}

ThreadLocal usage is a very useful technique to provide per thread contextual information. Used properly it's a valuable method that will come handy where applicable. 

No comments: