ThreadLocal使用

 Thread:

Thread类中有两个变量threadLocals和inheritableThreadLocals,两者都是ThreadLocal.ThreadLocalMap类型,默认情况下为null,对应源码为

1     ThreadLocal.ThreadLocalMap threadLocals = null;
2 
3     ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;ritableThreadLocals = null;

ThreadLocalMap:

ThreadLocalMap是ThreadLocal类的一个内部类,它的数据结构类似HashMap,key为当前的ThreadLocal对象(key的初始化是通过super(k)实现,也就是通过其父类WeakReference的构造函数实现,所以这里的key的引用类型为弱引用),value为Object类型,源码如下:

1         static class Entry extends WeakReference<ThreadLocal<?>> {
2             /** The value associated with this ThreadLocal. */
3             Object value;
4 
5             Entry(ThreadLocal<?> k, Object v) {
6                 super(k);
7                 value = v;
8             }
9         }

 ThreadLocal.set():

当线程调用ThreadLocal的set方法时,会根据获取当前Thread的threadLocals值,如果为null则初始化,如果不为null则将当前传入value塞入ThreadLocal中,源码如下:

1     public void set(T value) {
2         Thread t = Thread.currentThread();
3         ThreadLocalMap map = getMap(t);
4         if (map != null)
5             map.set(this, value);
6         else
7             createMap(t, value);
8     }

初始化过程为将当前ThreadLocal当做key,传入的值当做value赋值给当前Thread的threadlocals变量,源码如下:

1     void createMap(Thread t, T firstValue) {
2         t.threadLocals = new ThreadLocalMap(this, firstValue);
3     }

注意:当前线程的本地变量是放在线程的threadLocals变量里的(也就是Thread的变量里),而ThreadLocal本身类似一个工具壳,通过set将value添加到Thread的threadlocals的变量中。

ThreadLocal.get():

get方法会去获取当前线程的threadlocals变量,如果不为null,则直接返回ThreadLocalMap的value,如果为空,则初始化,源码如下:

 1  public T get() {
 2         Thread t = Thread.currentThread();
 3         ThreadLocalMap map = getMap(t);
 4         if (map != null) {
 5             ThreadLocalMap.Entry e = map.getEntry(this);
 6             if (e != null) {
 7                 @SuppressWarnings("unchecked")
 8                 T result = (T)e.value;
 9                 return result;
10             }
11         }
12         return setInitialValue();
13     }

其中threadlocals不为null,直接通过当前的TreadLocal值当做key去获取value。

如果threadlocals为null,则调用初始化方法,过程与set方法类似,只不过value赋值为null,源码如下:

 1   private T setInitialValue() {
 2         T value = initialValue();
 3         Thread t = Thread.currentThread();
 4         ThreadLocalMap map = getMap(t);
 5         if (map != null)
 6             map.set(this, value);
 7         else
 8             createMap(t, value);
 9         return value;
10     }

ThreadLocal.remove():

移除当前线程的ThreadLocal对象,包括ThreadLocalMap的key和value。

在上述set方法和treadlocal初始化的时候,entry对象的key的引用类型被传递给了WeakReference的构造函数,也就是key的引用类型为弱引用。

如果不调用ThreadLocal的remove方法释放对象的话,那么gc会回收当前ThreadLocalMap的ThreadLocal对象,则会出现ThreadLocalMap的key为null,但是value不为null的entry对象,则会造成内存泄漏。

threadlocals变量和inheritableThreadLocals的区别:

同一个ThreadLocal变量在父线程中被设置值后,在子线程中是获取不到的(threadLocals中为当前调用线程对应的本地变量,所以二者自然是不能共享的),InheritableThreadLocal可以实现共享。

InheritableThreadLocal实现父子线程变量共享的原因:

查看Thread类源码可以发现,在当前Thread进行init方法初始化的时候,会去调用currentThread获取父线程,我的理解是这个时候子线程还未创建完成,这个时候获取的currentThread仍是父线程,然后通过获取到的parent Thread获取父线程中的InheritableThreadLocal,将parent Thread中的InheritableThreadLocal赋值给当前线程的InheritableThreadLocal,由此完成父子线程间变量的共享,这个共享的实现其实也是获取变量然后重新复制一份给子线程实现的

posted @ 2024-02-16 15:02  leviH  阅读(1)  评论(0编辑  收藏  举报