ThreadLocal原理

ThreadLocal介绍

ThreadLocal是JDK包提供的,它提供了线程本地变量,也就是如果你创建了一个ThreadLocal变量,
那么访问这个变量的每个线程都会有这个变量的一个本地副本。当多个线程操作这个变量时,
实际操作的是自己本地内存里面的变量,从而避免了线程安全问题。

基本使用

threadOne:threadOne local variable
threadOne remove after :threadOne local variable
threadTwo:threadTwo local variable
threadTwo remove after :threadTwo local variable
  • 线程One中的代码通过set方法设置了local的值,这其实设置的是线程One本地内存中的一个副本
  • 这个副本线程Two是访问不了的。然后代码调用了print函数,代码通过get函数获取了当前线程(线程One)本地内存中local的值。

ThreadLocal实现原理

  • Thread类中有一个threadLocals和一个inheritableThreadLocals,它们都是ThreadLocalMap类型的变量,而ThreadLocalMap是一个定制化的Hashmap。
  • 在默认情况下,每个线程中的这两个变量都为null,只有当前线程第一次调用ThreadLocal的set或者get方法时才会创建它们。
  • 其实每个线程的本地变量不是存放在ThreadLocal实例里面,而是存放在调用线程的threadLocals变量里面。也就是说,ThreadLocal类型的本地变量存放在具体的线程内存空间中。
  • ThreadLocal就是一个工具壳,它通过set方法把value值放入调用线程的threadLocals里面并存放起来,当调用线程调用它的get方法时,再从当前线程的threadLocals变量里面将其拿出来使用。
  • 如果调用线程一直不终止,那么这个本地变量会一直存放在调用线程的threadLocals变量里面,所以当不需要使用本地变量时可以通过调用ThreadLocal变量的remove方法,从当前线程的threadLocals里面删除该本地变量。

ThreadLocal中的set,get,remove方法


首先获取调用线程,然后使用当前线程作为参数调用getMap(t)方法,getMap(Thread t)的代码如下
set()方法

ThreadLocalMap getMap(Thread t) {
     return t.threadLocals;
}
  • 可以看到,getMap(t)的作用是获取线程自己的变量threadLocals, threadlocal变量被绑定到了线程的成员变量上。
  • 如果getMap(t)的返回值不为空,则把value值设置到threadLocals中,也就是把当前变量值放入当前线程的内存变量threadLocals中。
  • threadLocals是一个HashMap结构,其中key就是当前ThreadLocal的实例对象引用,value是通过set方法传递的值。
  • 如果getMap(t)返回空值则说明是第一次调用set方法,这时创建当前线程的threadLocals变量。下面来看createMap(t, value)做什么。
 void createMap(Thread t, T firstValue) {
     t.threadLocals = new ThreadLocalMap(this, firstValue);
}

  • 它创建当前线程的threadLocals
    get()方法
  • 代码首先获取当前线程实例,如果当前线程的threadLocals变量不为null,则直接返回当前线程绑定的本地变量,否则执行代码进行初始化。setInitialValue()的代码如下。
  • 如果当前线程的threadLocals变量不为空,则设置当前线程的本地变量值为null,否则调用createMap方法创建当前线程的createMap变量。
    remove()
  • 如果当前线程的threadLocals变量不为空,则删除当前线程中指定ThreadLocal实例的本地变量。

总结

  • 在每个线程内部都有一个名为threadLocals的成员变量,该变量的类型为HashMap,其中key为我们定义的ThreadLocal变量的this引用,value则为我们使用set方法设置的值。
  • 每个线程的本地变量存放在线程自己的内存变量threadLocals中,如果当前线程一直不消亡,那么这些本地变量会一直存在,所以可能会造成内存溢出
  • 因此使用完毕后要记得调用ThreadLocalremove方法删除对应线程的threadLocals中的本地变量。

posted @ 2021-05-11 09:56  xiaoff  阅读(71)  评论(0)    收藏  举报