ThreadLocal简介

2016 Dec 3

在单线程的程序里,可以通过static变量或者singleton对象的方式定义全局的、共享的变量。 在多线程的程序里,如果想定义在一个线程内部共享的变量,可以考虑使用ThreadLocal

ThreadLocal instances are typically private static fields in classes that wish to associate state with a thread

一般来说,ThreadLocal对象会被声明成类的私有静态成员,比如下面这个例子来自ThreadLocal的javadoc

 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();
         }
     };

     // 不同的线程调用threadId.get()会返回不同的值,每个线程都有其各种的拷贝
     public static int get() {
         return threadId.get();
     }
 }
ThreadLocal的实现

每个线程对应的Thread对象里存在着一个map(所以不同线程的map相互隔离,没有竞争),

// 摘自Thread类的定义
ThreadLocal.ThreadLocalMap threadLocals = null;

ThreadLocalMap的实现是一个hash表,定义如下,

static class ThreadLocalMap {
	static class Entry extends WeakReference<ThreadLocal<?>> {
		/** The value associated with this ThreadLocal. */
		// ThreadLocal对象关联的对象
		Object value;
		
		Entry(ThreadLocal<?> k, Object v) {
			super(k);
			value = v;
		}		
	}
	
	private Entry[] table;
}      

map中的key由ThreadLocal对象们担当,value则是ThreadLocal对象所关联的对象。

下面是ThreadLocal::get()的伪代码(真实的实现考虑了threadLocals的lazy initialization),

public class ThreadLocal<T> {
    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap.Entry e = t.threadLocals.get(this);
        if (e == null) {
            t.threadLocals.set(this, this.initialValue());
        }
        return (T)e.value;
    }
} 
ThreadLocal和内存泄漏