Thread Local Storage

Thread local storage is a term for data that is accessible to anything that can access the thread, but that can hold a value that is unique in each thread. A common use for thread local storage is to give a different identifier to each of several newly constructed threads (as in, “if I am thread 5,...”) or tells them what they need to work on. ThreadLocal objects are typically private static variables used to associate some state with a thread (e.g., a user ID, session ID, or transaction ID).

Thread local storage was introduced with JDK 1.2 and allows each thread to have its own independently initialized copy of a variable. It's easy enough to give threads their own variables. The bit that's tricky is in getting them initialized with a value that's different for each thread in a thread-safe way. It's tough for the thread to do it because each copy of the same thread is (naturally) executing exactly the same code.

The following describes how you give your threads an int ID. You will create a subclass of ThreadLocal. You extend the ThreadLocal class and add members as needed. The unfamiliar thing in <anglebrackets> is a generic parameter:

class MyThreadLocal extends ThreadLocal <Integer>{
    private static int id = 0;

    // this method overrides a method in ThreadLocal
    protected synchronized Integer initialValue() {
        return id++;  // autoboxing at work for you.
    }

    // this method overrides a method in ThreadLocal
    public Integer get() {
        return super.get();
    }

}

We'll explain the use of generics in full in the next chapter. For now, it's a way of telling a class “this is the specific type I want you to work on in this subclass”. It's a way of getting better type checking than if you just use Object everywhere. Here the <Integer> says we providing an Integer to each thread. We can provide any object as thread local storage, including a container class (i.e. large amounts of data).

If you look at the API for java.lang.ThreadLocal, you'll see that it has an initialValue() method that we are overriding. Here, the underlying int is incremented each time the initialValue() method is called (so everyone gets a different initial value).

ThreadLocal also has get() and set() methods. An overriding version of get() is used, just to show explicitly that it is calling the ThreadLocal.get().

The following is our thread that uses local storage. It holds a static instance of the previous class:

class ThreadWithTLS extends Thread {
    private static MyThreadLocal tls = new MyThreadLocal();
    public void run() {
        System.out.println("My thread local value is " + tls.get());
    }
}

To show it in operation, we need a program that starts up a few of these threads, so you can see them get() different TLS values:

public class tls {

    public static void main(String args[]) {
       for(int i=0; i<5; i++)
            new ThreadWithTLS().start();
    }
}

When you try running the program you'll see each different thread has its own value for the integer that MyThreadLocal maintains.

% javac -source  1.5 tls.java
% java tls
My thread local value is 0
My thread local value is 1
My thread local value is 2
My thread local value is 3
My thread local value is 4

What's happening behind the scenes is that the class ThreadLocal is maintaining a table of threads versus values. Any thread can get its local value from the table and any thread can set a new value for itself into the table. The access is through tls.get() and tls.set(). The ThreadLocal class translates that into table lookup, indexed by thread ID. How does it know thread IDs? It's just the value returned by Thread.currentThread!

Wait—I hear you ask, “How does the initial value get set, since we didn't write a call to it?” It doesn't! At least, it doesn't until you call ThreadLocal's get() for the first time. When you do, it calls initialValue() as its first action to put a value in the table for you to get. That happens in each Thread.

Thread local storage is another thread idiom, and you won't use it in many (perhaps any) of your Java threaded programs. But when you want it, it is there. It's designed and implemented in a particularly clever way that makes it easy for the programmer to use, but also makes the maximum use of Java features to do all the work. The Thread API didn't change at all for the addition of thread local storage. It gets “two thumbs up” from this reviewer.

Thread local storage uses weak references (mentioned in chapter 10). The thread local storage has a table that connects threads with corresponding local storage data items. Each thread has a regular reference to the thread id that it uses for a key, and to the local storage entry. The table is a data structure that ties these together, allowing quick retrieval of an entry corresponding to a key. The thread has regular references, but the table just has weak references to all its keys/entries. A key and entry stay around as long as the strong references from the thread do. But when the thread ends, and is garbage collected, there are only now weak references to that key/entry in the table. Voila, key and entry are suddenly and automatically also candidates for garbage collection.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.172.38