javamultithreadingthread-local-storage

ThreadLocal<T> Documentation in JDK


JDK 1.6 documentation shows an example about how to use LocalThread<T>. I copy and paste it here:

For example, the class below generates unique identifiers local to each thread. A thread's id is assigned the first time it invokes UniqueThreadIdGenerator.getCurrentThreadId() and remains unchanged on subsequent calls.

 import java.util.concurrent.atomic.AtomicInteger; 

 public class UniqueThreadIdGenerator {    
     private static final AtomicInteger uniqueId = new AtomicInteger(0);    
     private static final ThreadLocal <Integer> uniqueNum = 
         new ThreadLocal <Integer> () {
             @Override 
             protected Integer initialValue() {
                 return uniqueId.getAndIncrement();
         }
     };

     public static int getCurrentThreadId() {
         return uniqueId.get();
     }
 } // UniqueThreadIdGenerator

My problem is:

when multiple threads call UniqueThreadIdGenerator.getCurrentThreadId() it only returns 0 because there is no initialization. Shouldn't it be like this:

public static int getCurrentThreadId() {
    return uniqueNum.get();
}

Now after the first call, it goes and initialize the variable.


Solution

  • Yes, it should be uniqueNum.get(). The JDK 7 docs get it right, and use better names:

    import java.util.concurrent.atomic.AtomicInteger;
    
    public class ThreadId {
        // Atomic integer containing the next thread ID to be assigned
        private static final AtomicInteger nextId = new AtomicInteger(0);
    
        // Thread local variable containing each thread's ID
        private static final ThreadLocal<Integer> threadId =
            new ThreadLocal<Integer>() {
                @Override protected Integer initialValue() {
                    return nextId.getAndIncrement();
            }
        };
    
        // Returns the current thread's unique ID, assigning it if necessary
        public static int get() {
            return threadId.get();
        }
    }
    

    It's not really a matter of initialization though - it's simply a matter of using the wrong member entirely. Even if lots of code had used uniqueNum in the original code, getCurrentThreadId() would always have returned "the next ID to be assigned" instead of "the ID assigned for the current thread".