ThreadLocal相当于提供了一种线程隔离,将变量与线程相绑定,它可以保证访问到的变量属于当前线程,每个线程都保存有一个变量副本,每个线程的变量都不同,而同一个线程在任何时候访问这个本地变量的结果都是一致的。当此线程结束生命周期时,所有的线程本地实例都会被GC。
ThreadLocal 的基本用法
public class ThreadLocal {
private static java.lang.ThreadLocal<Integer> seqNum = new java.lang.ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};
private int getNextNum() {
seqNum.set(seqNum.get() + 1);
return seqNum.get();
}
public static void main(String[] args) {
ThreadLocal sn = new ThreadLocal();
ThreadId t1 = new ThreadId(sn);
ThreadId t2 = new ThreadId(sn);
ThreadId t3 = new ThreadId(sn);
t1.start();
t2.start();
t3.start();
}
private static class ThreadId extends Thread {
private ThreadLocal sn;
public ThreadId(ThreadLocal sn) {
this.sn = sn;
}
@Override
public void run() {
for (int i = 0; i < 3 ; i++) {
System.out.println("thread[" + Thread.currentThread().getName() + "] --> sn["
+ sn.getNextNum() + "]");
}
}
}
}
输出结果
thread[Thread-0] --> sn[1]
thread[Thread-1] --> sn[1]
thread[Thread-1] --> sn[2]
thread[Thread-0] --> sn[2]
thread[Thread-0] --> sn[3]
thread[Thread-1] --> sn[3]
thread[Thread-2] --> sn[1]
thread[Thread-2] --> sn[2]
thread[Thread-2] --> sn[3]
ThreadLocal 源码
private final int threadLocalHashCode = nextHashCode();
/**
* The next hash code to be given out. Updated atomically. Starts at
* zero.
*/
private static AtomicInteger nextHashCode =
new AtomicInteger();
/**
* The difference between successively generated hash codes - turns
* implicit sequential thread-local IDs into near-optimally spread
* multiplicative hash values for power-of-two-sized tables.
*/
private static final int HASH_INCREMENT = 0x61c88647;
/**
* Returns the next hash code.
*/
private static int nextHashCode() {
return nextHashCode.getAndAdd(HASH_INCREMENT);
}
threadLocalHashCode 用来标识ThreadLocal的唯一性,每次hash操作的增量为0x61c88647。
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
通过当前线程t 来获取 ThreadLocalMap ,调用的方法是 getMap(t), getMap 的代码如下:
/**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
返回的是Thread 中的 threadLocals 属性,每个Thread里面都有一个ThreadLocal.ThreadLocalMap成员变量,也就是说每个线程通过ThreadLocal.ThreadLocalMap与ThreadLocal相绑定,这样可以确保每个线程访问到的thread-local variable都是本线程的。
第一次获取threadLocals 为空,这个时候调用
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;
}
我们来分析 createMap
/**
* Create the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @param firstValue value for the initial entry of the map
* @param map the map to store.
*/
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
下面分析 ThreadLocalMap ,它是ThreadLocal的静态内部类。
成员变量与常量
/**
* The initial capacity -- MUST be a power of two.
*/
private static final int INITIAL_CAPACITY = 16; //Map 的初始容量,必须是2的N次幂
/**
* The table, resized as necessary.
* table.length MUST always be a power of two.
*/
private Entry[] table; //用于存储数据
/**
* The number of entries in the table.
*/
private int size = 0; //table 中数据的数量
/**
* The next size value at which to resize.
*/
private int threshold; // Default to 0 //扩容时对应的阈值
下面分析存储数据的类Entry 代码如下 :
/**
* The entries in this hash map extend WeakReference, using
* its main ref field as the key (which is always a
* ThreadLocal object). Note that null keys (i.e. entry.get()
* == null) mean that the key is no longer referenced, so the
* entry can be expunged from table. Such entries are referred to
* as "stale entries" in the code that follows.
*/
static class Entry extends WeakReference<ThreadLocal> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
Entry类继承了WeakReference
ThreadLocalMap(ThreadLocal firstKey, Object firstValue) {
table = new Entry[INITIAL_CAPACITY];
int i = firstKey.threadLocalHashCode & (INITIAL_CAPACITY - 1);
table[i] = new Entry(firstKey, firstValue);
size = 1;
setThreshold(INITIAL_CAPACITY);
}
第一个参数就是本ThreadLocal实例(this),第二个参数就要保存的Value。构造函数首先创建一个长度为16的Entry数组,然后计算出firstKey对应的哈希值,然后存储到table中,并设置size和threshold。
剩下的操作就是对ThreadLocalMap操作,报考set get等
ThreadLocal 的分析到这里就结束了,下面看看用法