概要:
ThreadLocal一般被定义成private static的,这样的话,对于多线程还是web程序来说,在当前线程的任意阶段都可以操作(操作的是自己的局部变量,于其它线程是隔离的)。
设计原理:
1,Thread.java中保持了一个成员变量map
ThreadLocal.ThreadLocalMap threadLocals = null;
2,ThreadLocal第一次set时,创建第一步中的map, 该Map的key是ThreadLocal对象的弱引用
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
3,取值:
通过当前线程来取得map
根据当前ThreadLocal对象来取得value
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t); //通过当前线程来取得map
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this); //根据当前ThreadLocal对象来取得value
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
ThreadLocal基本操作
构造函数
ThreadLocal的构造函数签名是这样的:
/**
* Creates a thread local variable.
* @see #withInitial(java.util.function.Supplier)
*/
public ThreadLocal() { }
内部啥也没做。
initialValue函数
initialValue函数用来设置ThreadLocal的初始值,函数签名如下:
protected T initialValue() {
return null; }
该函数在调用get
函数的时候会第一次调用,但是如果一开始就调用了set
函数,则该函数不会被调用。通常该函数只会被调用一次,除非手动调用了remove
函数之后又调用get
函数,这种情况下,get
函数中还是会调用initialValue
函数。该函数是protected类型的,很显然是建议在子类重载该函数的,所以通常该函数都会以匿名内部类的形式被重载,以指定初始值,比如:
package com.winwill.test;
/**
* @author qifuguang
* @date 15/9/2 00:05 */ public class TestThreadLocal { private static final ThreadLocal<Integer> value = new ThreadLocal<Integer>() { @Override protected Integer initialValue() { return Integer.valueOf(1); } }; }
remove操作
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
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);
}