threadlocal用于创建线程的本地变量,threadlocal实现原理和用途
目录
线程本地是什么?绑定实现原理分析绑定内存泄漏问题
ThreadLocal是什么?
线程本地使得我们可以创建线程私有的变量,这个变量相对于其他线程来说是不可见的,线程本地为变量在每个线程中都创建了一个副本,每个线程可以访问自己私有的线程变量,代码示例如下:
公共类ThreadLocalDemo { //创建一个绑定对象,用来为每个线程会复制保存一份变量,实现线程封闭private static thread local Integer local num=new thread local Integer(){ @ Override protected Integer初始值(){ return 1;} };公共静态void main(String[] args) { //线程0新线程(){ @覆盖公共void run(){本地编号。集合(1);试试{线程。睡眠(2000);} catch(中断异常e){ e . printstacktrace();}本地号码。设置(本地号码。get()10);系统。出去。println(线程。当前线程().getName() : 本地号码。get());//11 } }.start();//线程1个新线程(){ @ Override public void run(){ local num。集合(3);试试{线程。睡眠(2000);} catch(中断异常e){ e . printstacktrace();}本地号码。设置(本地号码。get()20);系统。出去。println(线程。当前线程().getName() : 本地号码。get());//23 } }.start();系统。出去。println(线程。当前线程().getName() : 本地号码。get());//0 }}如上所述,算上主要的线程与新建的两个线程,总共三个线程,每个线程都包含自己的私有变量,此处我们设置值1、设定()和获取()方法用来设置值和获得值,执行结果如下:
ThreadLocal实现原理分析
线程本地是一个泛型类,可以接受任何类型的对象,其内部维护了一个ThreadLocalMap的静态内部类,我们使用的get(),set()等其实都来自这个类,每次都会为当前线程创建一个ThreadLocalMap对象,用来记录私有的值
先看集合()方法
公共空集(T值){ //拿到当前线程螺纹t=螺纹。currentthread();//拿到当前线程map ThreadLocalMap map=get map(t);如果(图!=null) //存在设置值map.set(this,value);else //不存在则创建createMap(t,value);}void createMap(Thread t,T firstValue) { //threadLocals属性即为此map t . thread locals=新的线程局部映射(this,first value);}接着是获取()方法
public T get() { //拿到当前线程螺纹t=螺纹。currentthread();//拿到当前线程对应的map ThreadLocalMap map=get map(t);//如果已有地图如果(地图!=null) { //取值操作,拿到对应的条目ThreadLocalMap .条目e=地图。获取词条(本);如果(e!=null){ @ suppress warnings(未检查)T result=(T)e . value;返回结果;} } //没有地图,则去创建初始化一个地图返回set initial value();} private T set initial value(){//初始值()方法返回的价值为零T值=初始值();//拿到当前线程去创建对应的映射线程t=线程。当前线程();ThreadLocalMap map=get map(t);如果(图!=null) map.set(this,value);否则createMap(t,value);返回值;}线程本地可以理解为对ThreadLocalMap的封装
ThreadLocal内存泄漏问题
在ThreadLocalMap中,使用绑定的弱引用作为键
这样的话,如果一个绑定不存在外部强引用时,那么键注定要被乔治勋章回收,这样导致ThreadLocalMap中键为空,而价值还存在着强引用链
一个线程可以同时拥有多个ThreadLocal。如果值在作为弱引用的键被回收后不能被回收,那么这个ThreadLocal的生命周期就和这个线程一样长(因为这个值的强引用链在线程结束后会被打断)。如果线程永远不会结束,累积的值无法回收,那么就会出现内存泄漏问题。
这里的解决方案是:在每次使用完ThreadLocal时调用它的remove()方法来清除数据。
public void remove(){ thread local map m=get map(thread . current thread());如果(m!=null)m . remove(this);}这里,我们来看看key作为强引用或弱引用的区别。
如果把键作为强引用,它的生命周期和线程一样长,有一个稳定的强引用链,不能回收,导致内存泄漏。如果作为弱引用,GC会自动回收它们,后续的remove()方法也可以更好的回收值。所以我们一般把ThreadLocal设计成私有静态,用remove()方法在用完后手动删除它们。
关于Java中ThreadLocal线程变量的实现的这篇文章到此结束。有关Java ThreadLocal线程变量的更多信息,请搜索以前关于流行IT的文章或继续浏览下面的相关文章。我希望你以后能更多地支持流行音乐!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。