ThreadLocal类为线程提供局部变量,每一个线程都有它自己的、独立初始化的变量副本,这个变量通过get和set方法访问。
主要方法分析:
initialValue()
protected T initialValue() {
return null;
}
该方法返回当前线程局部变量的初始化值。当第一次使用get方法访问变量时调用该方法,但若该线程在这之前调用了set方法,则不会调用initialValue方法。正常情况下,该方法最多被调用一次,但是如果后续调 用了remove,然后再调用get,则该方法可能再次被调用。
withInitial()
public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
return new SuppliedThreadLocal<>(supplier);
}
用于创建一个线程局部变量,变量的初始化值通过调用Supplier的get方法来确定,例子如下:
import java.util.function.Supplier;
public class ThreadLocalDemo {
public static void main(String args[]) {
ThreadLocal<Integer> tl = ThreadLocal.withInitial(new Supplier<Integer>() {
@Override
public Integer get() {
// TODO Auto-generated method stub
return new Integer(8);
}
});
System.out.println(tl.get());
}
}
输出为:8
get()
public T get() {
//获取当前线程
Thread t = Thread.currentThread();
//获取当前线程的ThreadLocalMap对象
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();
}
返回当前线程的局部变量副本的值,如果此变量没有值,那么会调用initialValue方法初始化,setInitialValue()方法实现如下:
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
//map里存储的value为对应的key为当前ThreadLocal对象
map.set(this, value);
else
createMap(t, value);
return value;
}
set()
public void set(T value) {
//获得当前线程
Thread t = Thread.currentThread();
//获取当前线程的ThreadLocalMap对象
ThreadLocalMap map = getMap(t);
//若map不为空,将value存入map
if (map != null)
map.set(this, value);
else
//map为空,创建一个ThreadLocalMap,并将value存入map
createMap(t, value);
}
设置当前线程局部变量副本的值
remove()
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
//清除value
m.remove(this);
}
该方法用于清除当前线程局部变量的值。变量值被清除后,若当前线程随后通过get读取该变量的值,则initialValue方法会再次被调用对变量进行初始化,除非在此期间调用了set方法。
经过上面的分析,可知通过ThreadLocal创建的变量是维护在线程内部的,这就意味着线程只要不退出,那么对象的引用将一直存在。当线程退出的时候会进行一些清理工作,如下所示:
private void exit() {
if (group != null) {
group.threadTerminated(this);
group = null;
}
/* Aggressively null out all reference fields: see bug 4006245 */
target = null;
//加速资源清理,threadLocals为ThreadLocal.ThreadLocalMap类型
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
此方法为private型,通过系统调用,给线程一个机会在其实际退出之前清理资源。
上面多次出现了ThreadLocalMap类,有必要说明一下。ThreadLocalMap的实现采用了弱引用,弱引用在垃圾回收的时候被发现就会被回收。ThreadLocalMap内部由一系列的Entry构成,每一个Entry都是WeakReference<ThreadLocal>类型的:
static class Entry extends WeakReference<ThreadLocal<?>> {
Object value;
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
}
内部维护一个Entry数组,用于存放线程的变量
private Entry[] table;
例子:
public class ThreadLocalDemo implements Runnable{
private static ThreadLocal<Integer> tl=new ThreadLocal<Integer>();
@Override
public void run() {
// TODO Auto-generated method stub
if(tl.get()==null)
tl.set(new Integer(1));
System.out.print(tl.get()+"\t");
}
public static void main(String args[]) {
int k=0;
for(int i=0;i<1000;i++) {
Thread t=new Thread(new ThreadLocalDemo());
t.start();
}
}
}
输出全为1,即每一个线程都维护自己的一个变量副本