浅谈threadlocal
1.什么是threadlocal?
ThreadLocal叫做线程变量,意思是ThreadLocal中填充的变量属于当前线程,该变量对其他线程而言是隔离的。ThreadLocal为变量在每个线程中都创建了一个副本,那么每个线程可以访问自己内部的副本变量。
1、set方法源码
1 public void set(T value) {
2 //(1)获取当前线程(调用者线程)
3 Thread t = Thread.currentThread();
4 //(2)以当前线程作为key值,去查找对应的线程变量,找到对应的map
5 ThreadLocalMap map = getMap(t);
6 //(3)如果map不为null,就直接添加本地变量,key为当前定义的ThreadLocal变量的this引用,值为添加的本地变量值
7 if (map != null)
8 map.set(this, value);
9 //(4)如果map为null,说明首次添加,需要首先创建出对应的map
10 else
11 createMap(t, value);
12 }
在上面的代码中,(2)处调用getMap方法获得当前线程对应的threadLocals(参照上面的图示和文字说明),该方法代码如下
ThreadLocalMap getMap(Thread t) {
return t.threadLocals; //获取线程自己的变量threadLocals,并绑定到当前调用线程的成员变量threadLocals上
}
如果调用getMap方法返回值不为null,就直接将value值设置到threadLocals中(key为当前线程引用,值为本地变量);如果getMap方法返回null说明是第一次调用set方法(前面说到过,threadLocals默认值为null,只有调用set方法的时候才会创建map),这个时候就需要调用createMap方法创建threadLocals,该方法如下所示
1 void createMap(Thread t, T firstValue) {
2 t.threadLocals = new ThreadLocalMap(this, firstValue);
3 }
createMap方法不仅创建了threadLocals,同时也将要添加的本地变量值添加到了threadLocals中。
2、get方法源码
在get方法的实现中,首先获取当前调用者线程,如果当前线程的threadLocals不为null,就直接返回当前线程绑定的本地变量值,否则执行setInitialValue方法初始化threadLocals变量。在setInitialValue方法中,类似于set方法的实现,都是判断当前线程的threadLocals变量是否为null,是则添加本地变量(这个时候由于是初始化,所以添加的值为null),否则创建threadLocals变量,同样添加的值为null。
1 public T get() {
2 //(1)获取当前线程
3 Thread t = Thread.currentThread();
4 //(2)获取当前线程的threadLocals变量
5 ThreadLocalMap map = getMap(t);
6 //(3)如果threadLocals变量不为null,就可以在map中查找到本地变量的值
7 if (map != null) {
8 ThreadLocalMap.Entry e = map.getEntry(this);
9 if (e != null) {
10 @SuppressWarnings("unchecked")
11 T result = (T)e.value;
12 return result;
13 }
14 }
15 //(4)执行到此处,threadLocals为null,调用该更改初始化当前线程的threadLocals变量
16 return setInitialValue();
17 }
18
19 private T setInitialValue() {
20 //protected T initialValue() {return null;}
21 T value = initialValue();
22 //获取当前线程
23 Thread t = Thread.currentThread();
24 //以当前线程作为key值,去查找对应的线程变量,找到对应的map
25 ThreadLocalMap map = getMap(t);
26 //如果map不为null,就直接添加本地变量,key为当前线程,值为添加的本地变量值
27 if (map != null)
28 map.set(this, value);
29 //如果map为null,说明首次添加,需要首先创建出对应的map
30 else
31 createMap(t, value);
32 return value;
33 }
remove方法判断该当前线程对应的threadLocals变量是否为null,不为null就直接删除当前线程中指定的threadLocals变量
1 public void remove() {
2 //获取当前线程绑定的threadLocals
3 ThreadLocalMap m = getMap(Thread.currentThread());
4 //如果map不为null,就移除当前线程中指定ThreadLocal实例的本地变量
5 if (m != null)
6 m.remove(this);
7 }
①强引用:Java中默认的引用类型,一个对象如果具有强引用那么只要这种引用还存在就不会被GC。
②软引用:简言之,如果一个对象具有弱引用,在JVM发生OOM之前(即内存充足够使用),是不会GC这个对象的;只有到JVM内存不足的时候才会GC掉这个对象。软引用和一个引用队列联合使用,如果软引用所引用的对象被回收之后,该引用就会加入到与之关联的引用队列中
③弱引用(这里讨论ThreadLocalMap中的Entry类的重点):如果一个对象只具有弱引用,那么这个对象就会被垃圾回收器GC掉(被弱引用所引用的对象只能生存到下一次GC之前,当发生GC时候,无论当前内存是否足够,弱引用所引用的对象都会被回收掉)。弱引用也是和一个引用队列联合使用,如果弱引用的对象被垃圾回收期回收掉,JVM会将这个引用加入到与之关联的引用队列中。若引用的对象可以通过弱引用的get方法得到,当引用的对象呗回收掉之后,再调用get方法就会返回null
④虚引用:虚引用是所有引用中最弱的一种引用,其存在就是为了将关联虚引用的对象在被GC掉之后收到一个通知。(不能通过get方法获得其指向的对象)


浙公网安备 33010602011771号