ThreadLocal源码解析

160 阅读2分钟
ThreadLocal类的作用:为每个线程创建独立的副本,从而保证了线程安全。

ThreadLocal使用代码示例:
[JavaScript]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class MyThreadLocalTest {
private ThreadLocal<Integer> threadLocal=new ThreadLocal<Integer>(){
@Override
protected Integer initialValue() {
return 1;
}
};
public void StartThreadArray(){
Thread[] runs = new Thread[5];
for(int i=0;i<runs.length;i++){
runs[i]=new Thread(new MyThreadLocalTest.TestThread(1));
}
for(int i=0;i<runs.length;i++){
runs[i].start();
}
}
public class TestThread implements Runnable{
int id;
public TestThread(int id){
this.id = id;
}
public void run() {
System.out.println("this is :"+Thread.currentThread().getName()+":start");
Integer s = threadLocal.get();
s = s+id;
threadLocal.set(s);
System.out.println("this is :"+Thread.currentThread().getName()
+":"+ threadLocal.get());
}
}
public static void main(String[] args){
MyThreadLocalTest test = new MyThreadLocalTest();
test.StartThreadArray();
}
}

源码解析:
当使用ThreadLocal时,线程第一次调用ThreadLocal的get()方时,ThreadLocal对象会先获取当前线程对象,然后根据调用getMap(Thread t) 方法,从线程中获取到ThreadLocalMap对象(这个对象其实就是线程中的ThreadLocal对象和TheadLocal中的元素的绑定关系,类似于一个Map集合),第一次调用get()方法时该对象为空null,因为还未建立映射关系,此时对调用到setInitialValue()。
[JavaScript]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
11
12
13
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();
}


该方法会首先调用到initialValue(),你定义初始化的值,然后从线程中获取ThreadLocalMap对象,判断对象是否为空,如果为空则新建一个ThreadLocalMap对象并且调用createMap(Thread t,T value)方法。
该方法主要的作用是创建一个ThreadLocalMap对象,并且建立当前ThreadLocal对象以及初始化节点的对应关系,并且将这个ThreadLocalMap对象放入线程中的。
如果线程中的ThreadLocalMap对象不为空,则将当前ThreadLocal对象和初始化节点的映射关系放入ThreadLocalMap中。
[JavaScript]
纯文本查看
复制代码
01
02
03
04
05
06
07
08
09
10
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方法。当线程第二次调用get()方法时,就直接从线程中的ThreadLocalMap中获取值。

具体调用流程为: