ThreadLocal类提供线程局部变量。这些变量和其他普通的变量的区别在于,每个线程获取的线程局部变量都拥有自己相对独立的初始化过的副本。ThreadLocal的实例通常被声明为private static 来希望达到关联线程的状态的目的(例如:userId,transaction id)。
按我本人的理解有两点注意:
第一:ThreadLocal提供的线程局部变量通常都是新new的。这个他们都是初始一样的,最后和线程关联的,相对独立的。
第二:ThreadLocal是为了解决线程内部数据共享,而不是为了解决线程间数据共享(synchronized).将同一个引用分别放到不同线程的threadLoca变量中,一个改变,都改变。
看一下ThreadLocal的成员变量
private final int threadLocalHashCode = nextHashCode(); private static AtomicInteger nextHashCode = new AtomicInteger(); private static final int HASH_INCREMENT = 0x61c88647; private static int nextHashCode() { return nextHashCode.getAndAdd(HASH_INCREMENT); }
每个threadLocal有一个threadLocalHashCode变量,每个ThreadLocal实例的threadLocalHashCode值都是不一样的,每次都是在上次的基础上增加HASH_INCREMENT。至于为什么是这个数,主要是为了解决
冲突问题,这个特殊的hash值是定制化的。
ThreadLocal对象的重要方法解析
先看set方法及其相关方法:
public void set(T value) { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); } ThreadLocalMap getMap(Thread t) { return t.threadLocals; } void createMap(Thread t, T firstValue) { t.threadLocals = new ThreadLocalMap(this, firstValue); }
ThreadLocal调用set的过程就是:获取当前线程对象的ThreadLocalMap变量,如果存在就以ThreadLocal实例为key,传入的值为value存入ThreadLocalMap变量。如果不存在就new一个ThreadLocalMap对象,并且赋给当前线程对象。
再看get如何获取:
public T get() { Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) { ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } return setInitialValue(); } private T setInitialValue() { T value = initialValue(); Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
get的过程是:获取当前线程实例的ThreadLocalMap变量,它是一个map,之前存的时候是以threadlocal对象作为key的,现在先试图通过这个key(也就是this),获取ThreadLocalMap.Entry类型的值。如果获取不为空,返回value,如果为空,说明之前没有存,这个时候调用setInitialValue()。这个方法调用initialValue()方法,初始化value,以ThreadLocal对象为key(也就是this), value为值,初始化ThreadLocalMap,并返回value.
再看一下ThreadLocal对象的remove方法
public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }
remove的过程就是调用ThreadLocalMap的remove方法,移除以threadlocal为key的值。
至此,我们发现,调用ThreadLocal的方法,其实内部是调用本线程实例对象(Thread)的ThreadLocalMap成员变量的想关方法实现的.因此,ThreadLocalMap才是理解线程局部变量的关键。