精通高并发与多线程,却不会用ThreadLocal?( 三 )

执行流程:

  • 首先获取当前线程 , 并根据当前线程获取一个 map
  • 如果获取的 map 不为空 , 则将参数设置到 map 中(当前 ThreadLocal 的引用作为 key )
  • 如果 Map 为空 , 则给该线程创建 map, 并设置初始值
get 方法源码如下:
public T get() {// 获取当前线程对象Thread t = Thread.currentThread();// 获取此线程对象中维护的ThreadLocalMap对象ThreadLocalMap map = getMap(t);// 如果此map存在if (map != null) {// 以当前的ThreadLocal 为 key , 调用getEntry获取对应的存储实体eThreadLocalMap.Entry e = map.getEntry(this);// 对e进行判空if (e != null) {@SuppressWarnings("unchecked")// 获取存储实体 e 对应的 value值// 即为我们想要的当前线程对应此ThreadLocal的值T result = (T)e.value;return result;}}return setInitialValue();}private T setInitialValue() {// 调用initialValue获取初始化的值// 此方法可以被子类重写, 如果不重写默认返回nullT value = http://kandian.youth.cn/index/initialValue();// 获取当前线程对象Thread t = Thread.currentThread();// 获取此线程对象中维护的ThreadLocalMap对象ThreadLocalMap map = getMap(t);// 判断map是否存在if (map != null)// 存在则调用map.set设置此实体entrymap.set(this, value);else// 如果当前线程不存在ThreadLocalMap对象则调用createMap进行ThreadLocalMap对象的初始化// 并将 t(当前线程)和value(t对应的值)作为第一个entry存放至ThreadLocalMap中createMap(t, value);// 返回设置的值valuereturn value;}复制代码执行流程:
  • 首先获取当前线程 , 根据当前线程获取一个 map
  • 如果获取的 map 不为空 , 则在 map 中以 ThreadLocal 的引用作为 key 来在 map 中获取对应的 Entry entry, 否则跳转到第四步
  • 如果 Entry entry 不为空, 则返回 entry.value, 否则跳转到第四步
  • map 为空或者 entry 为空 , 则通过 initialValue 函数获取初始值 value, 然后用 ThreadLocal 的引用和 value 作为 firstKey 和 firstValue 创建一个新的 map
remove 方法源码如下:
public void remove() {// 获取当前线程对象中维护的ThreadLocalMap对象ThreadLocalMap m = getMap(Thread.currentThread());// 如果此map存在if (m != null)// 存在则调用map.removem.remove(this);}// 以当前ThreadLocal为key删除对应的实体entryprivate void remove(ThreadLocal key) {Entry[] tab = table;int len = tab.length;int i = key.threadLocalHashCodefor (Entry e = tab[i];e != null;e = tab[i = nextIndex(i, len)]) {if (e.get() == key) {e.clear();expungeStaleEntry(i);return;}}}复制代码执行流程:
  • 首先获取当前线程 , 并根据当前线程获取一个 map
  • 如果获得的map 不为空 , 则移除当前 ThreadLocal 对象对应的 entry
initialValue 方法源码如下:
protected T initialValue() {return null;}复制代码在源码中我们可以看到这个方法仅仅简单的返回了 null, 这个方法是在线程第一次通过 get () 方法访问该线程的 ThreadLocal 时调用的 , 只有在线程先调用了 set () 方法才不会调用 initialValue () 方法 , 通常情况下 , 这个方法最多被调用一次 。
如果们想要 ThreadLocal 线程局部变量有一个除 null 以外的初始值 , 那么就必须通过子类继承 ThreadLocal 来重写此方法 , 可以通过匿名内部类实现 。
【END】
这篇 ThreadLocal 就介绍到这里啦 , 希望读到这里的小伙伴能够有所收获 。