ThreadLocal是干嘛用的?

您所在的位置:网站首页 滩涂干嘛用的 ThreadLocal是干嘛用的?

ThreadLocal是干嘛用的?

2024-07-16 23:37| 来源: 网络整理| 查看: 265

ThreadLocal是通过将变量设置成Thread的局部变量,即使用该变量的线程提供一个独立的副本,可以独立修改,不会影响其他线程的副本,这样来解决多线程的并发问题。ThreadLocal主要是线程不安全的类在多线程中使用,一般常用于数据库连接和Session管理。看下ThreadLocal的官方注释:

{@code ThreadLocal} instances are typically private * static fields in classes that wish to associate state with a thread (e.g., * a user ID or Transaction ID).//就是说ThreadLocal一般是作为private static变量来使用的,用于标记一个线程的一些状态

 

自己写的demo以及运行结果如下:

可以看出,打印出来的值是不一样的,这个是为什么?来分析下它的源码

 

点到ThreadLocal里面看了下,发现它是Thread类内部的一个属性:

/* ThreadLocal values pertaining to this thread. This map is maintained * by the ThreadLocal class. */ ThreadLocal.ThreadLocalMap threadLocals = null;//本片主角 /* * InheritableThreadLocal values pertaining to this thread. This map is * maintained by the InheritableThreadLocal class. */ ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;//使用它可以实现子线程可以获取父线程中的ThreadLocal变量

 

来看下ThreadLocal的Set()方法:

这里getMap其实获取的就是上面的ThreadLocal.ThreadLocalMap threadLocals,然后讲ThreadLocal的引用设置进去。

 

再来看下它的get()方法

:

    也是获取到当前线程的ThreadLocalMap变量,然后讲当前ThreadLocal做为key,想要保存的值作为value设置到map中。

 

总结下个人理解:

    每个线程的内部都会有一个ThreadLocalMap的变量。当我们使用同一个ThreadLocal时,实际上每次都是往不同的map中设置值,只是这些map的key都是同一个。这样自然就不会有线程安全问题了,因为我们使用的是value,不是key!!!

    为什么要使用map是因为一个线程可以有不止一个的ThreadLocal变量。

 

同时也说明了一个问题,value是存在线程安全问题的:

看如下这个例子

public class ThreadLocalTest { private static ThreadLocal threadLocal = new ThreadLocal(); private static List list = new ArrayList(); public static void main(String[] args) { list.add(0); threadLocal.set(list); System.out.println(threadLocal.get()); for (int i = 0; i < 1; i++) { new Thread(new MyThread()).start(); } } static class MyThread implements Runnable { @Override public void run() { threadLocal.set(list); System.out.println(threadLocal.get().get(0)); } } }

看下它的输出:

可以看到MyThread线程中获取到了主线程中的值,所以使用ThreadLocal时,每个线程对应的value得是不同的,不能是共享的变量!

 

 

ThreadLocal为什么会引发内存泄露问题:

    我们已经知道,ThreadLocal变量最终是设置到了Thread的ThreadLocalMap中。Key是ThreadLoacl变量的引用,Value是设置到ThreadLocal中的值。但是要注意的是,这个Key是一个弱引用:

 

为什么Key要设置成弱引用?来看下ThreadLocal内存结构图:

    个人理解是,当ThreadLocal被废弃时,可以回收掉当前ThreadLocalMap中的Key。这个时候,如果再有对这个ThreadLocal的操作,那么就会把原先的Value置为null,然后会在下一次GC的时候回收掉。

    但是,如果ThreadLocal引用变为null之后,不再对这个ThreadLocal变量进行操作了。那么就会由于Value这个强引用一直存在,一直都会有内存泄露的问题,个人理解这个就是ThreadLocal内存泄露的本质。

    所以,最好的办法就是ThreadLocal使用完毕之后,手动调用remove方法将其回收掉。

 

 

 

 

参考:

    https://www.zhihu.com/question/23089780(ThreadLocal和Synchroniezd区别)

    https://www.cnblogs.com/chenkeyu/p/7623653.html(ThreadLocal中放置Session)

    https://blog.csdn.net/tmr1016/article/details/100141446(ThreadLocal内存结构图)

 

 



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3