JDK源码(二十):ThreadLocal

Posted jdkSpring

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JDK源码(二十):ThreadLocal相关的知识,希望对你有一定的参考价值。

ThreadLoc al类并不是用来解决多线程环境下的共享变量问题,而是用来提供线程局部变量。这些变量与普通的变量不同,因为每个访问一个变量的线程(通过其get或set方法)都有自己的、独立初始化的变量副本。 ThreadLoc al实例通常是类中的私有静态字段,希望将状态与线程关联(例如,用户ID或事务ID)。每个线程都保持对线程本地变量的副本的隐式引用,只要线程是活的并且ThreadLocal 实例是可访问的;在线程离开之后,线程本地实例的所有副本都受到垃圾回收(除非存在对这些副本的其他引用)。

实现原理

ThreadLocal实现方式就是ThreadLocal类内部有一个线程安全的ThreadLocalMap,然后用ThreadLocal本身作为Map的key,实例对象作为Map的value,这样就能达到各个线程的值隔离的效果。

ThreadLocalMap

ThreadLocalMap是用来存储与线程关联的value的哈希表,它具有HashMap的部分特性,比如容量、扩容、删除等,它内部通过Entry类来存储key和value。
static class Entry extends WeakReference<ThreadLocal<?>> {    /** 与此ThreadLocal关联的值. */    Object value; Entry(ThreadLocal<?> k, Object v) { super(k); value = v; }}

Entry继承自WeakReference,可以知道,ThreadLocalMap是使用ThreadLocal的弱引用作为Key的。如果一个ThreadLocal没有外部关联的强引用,那么在虚拟机进行垃圾回收时,这个ThreadLocal会被回收,这样,ThreadLocalMap中就会出现key为null的Entry,这些key对应的value也就再无妨访问,但是value却存在一条从Current Thread过来的强引用链。因此只有当Current Thread销毁时,value才能得到释放。

ThreadLocalMap采用线性探查的方式来处理哈希冲突,所以会有一个while循环去查找对应的key,在查找过程中,若发现key为null,即通过弱引用的key被回收,会调用expungeStaleEntry(int)方法,若key为null,则该方法会清理与key对应的value以及Entry。

类名

public class ThreadLocal<T>

变量

set(T value)

public void set(T value) {//返回当前正在执行的线程对象的引用 Thread t = Thread.currentThread();//获取线程对应的ThreadLocalMap对象     ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value);}

当map为null时,调用createMap创建一个map。

createMap(Thread t, T firstValue)

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

可以看出createMap是初始化当前线程的threadLocals变量。所以并不是ThreadLocal中存储线程,而是线程中存储ThreadLocal。

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();}

简单应用

很多时候我们会用SimpleDateFormat来格式化时间,而SimpleDateFormat其实是线程不安全的,我们可以用ThreadLocal封装一个时间工具类。

JDK源码(二十):ThreadLocal

ThreadLocal源码(jdk1.8)

以上是关于JDK源码(二十):ThreadLocal的主要内容,如果未能解决你的问题,请参考以下文章

JDK1.8中ThreadLocal源码解析

JDK1.8中ThreadLocal源码解析

ThreadLocal深入JDK源码之ThreadLocal类

ThreadLocal总结(jdk1.8源码)

大白话讲解JDK源码系列:从头到尾再讲一遍ThreadLocal

Java -- 基于JDK1.8的ThreadLocal源码分析