ThreadLocal类提供线程局部变量,每一个访问这种变量的线程(通过get和set方法),都有独立初始化的变量副本。可以保证存储进去的数据,只被当前线程读取,各线程之间不会相互影响。
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();
}
//getMap方法
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
static class Entry extends WeakReference> {
Object value;
Entry(ThreadLocal> k, Object v) {
super(k);
value = v;
}
}
TreadLocal存储在每一个线程的ThreadLocal的ThreadLocalMap里,ThreadLocalMap包含一个Entry数组,并且每个Entry数组存储一个ThreadLocal和其value值。
ThreadLocal提供了get和set方法,set方法向当前线程ThreadLocal.ThreadLocalMap类型的成员变量threadLocals中设置值,key就是ThreadLocal,value就是要设置的值。也就是说,set方法中操作的是ThreadLocal为key,指定值为value,最后将键值对封装成Entry对象放到ThreadLcoal.ThreadLocalMap对象中。
正常情况下,使用线程创建ThreadLocal对象,线程生命周期结束,此时Thread的ThreadLocal对象也会被回收,但是如果使用线程池,有时核心线程会被循环使用,此时有可能会造成内存泄漏
Entry继承了WeakReference,可以知道ThreadLocalMap使用的是ThreadLcoal的弱引用作为key,这样当ThreadLcoal置null后,没有任何强引用指向ThreadLcoal实例,可以顺利被gc回收。否则会造成内存泄漏。但是此时value依然为强引用,所以使用完要用remove方法。
换句话说,在线程池中使用ThreadLocal,ThreadLocalMap中含有多个ThreadLocal–value的Entry,value是强引用,有可能回收不了,需要手动remove
get方法返回当前线程的ThreadLocal变量副本的值。也就是取出每一个Entry对象中,key为ThreadLcoal的对应value值。
demo:
public class Test{
public static void main(String[] args) {
ThreadA a1 = new ThreadA();
a1.setName("thread1");
a1.start();
ThreadA a2 = new ThreadA();
a1.setName("thread2");
a2.start();
}
static class ThreadA extends Thread{
private static ThreadLocal a = new ThreadLocal<>();
@Override
public void run() {
for(int i=0;i<3;i++){
a.set(i);
System.out.println("thread[" +Thread.currentThread().getName()+"]--->" +a.get());
}
}
}
}
thread[thread2]--->0
thread[thread2]--->1
thread[thread2]--->2
thread[Thread-1]--->0
thread[Thread-1]--->1
thread[Thread-1]--->2



