ThreadLocal介绍:

  • ThreadLocal提供了线程的局部变量,让每个线程都能够通过get/set办法来对局部变量的数据进行操作,不会和其余线程的局部变量产生抵触,实现了线程的数据隔离,比方超市的公共储物柜,每个人都能够应用,然而每个人的物品有都是分隔开来的

ThreadLocal实现原理:

  1. 通过源码能够察看到,当调用ThreadLocal的set办法时,去调用了getMap办法,传入了以后线程,返回了ThreadLocalMap

    • 这个ThreadLocalMap其实就是存在于Thread类外面的一个Map
  2. 获取到ThreadLocalMap之后,将本人(ThreadLocal)作为key,值作为value放入ThreadLocalMap中,这样就能起到线程之间数据隔离的成果

发问工夫:

Thread有什么用呢?或者说利用场景在哪?

  • 在我的项目中,ThreadLocal的确 很(根)少(本)用(不)到(用),在Spring中有ThreadLocal的实现,ThreadLocal存储的是一个Map,Map外面是一个个的Entry,在Spring中实现中,Entry中的Key寄存的是DataSource,Value寄存的是Connection,用ThreadLocal是为了保障一个线程获取一个Connection连贯对象,从而就能保障一次事务内所有的操作都是在同一个数据库连贯上

刚刚提到ThreadLocalMap是定义在Thread中的,那么我能够在ThreadLocal中定义这个Map,将以后线程作为key,值作为value,不也能实现线程之间数据隔离吗?如下图:

  • 实践上来说是能够的,然而要思考以下三点

    1. 每个线程都会有多个公有变量,既然要以以后线程为Key,那么就要辨别多个变量,须要保护一个标识
    2. 就算解决了保护标识的问题,还有就是当并发足够大时,多个线程来拜访本人存储的公有变量时,多个线程拜访这个Map,可能会导致Map体积收缩,从而导致Map的拜访性能有所降落
    3. 而且这个Map保护着所有线程的公有变量,所以不晓得什么时候能够销毁它

为什么key要用弱援用指向ThreadLocal对象?什么是弱援用?

  • 首先,先介绍一下Java的四中援用:Java有强、软、弱、虚四中援用

    1. 强援用(NormalReference):强引指向一个对象时,只有对象没有被置为null,那么在GC时就不会被回收
    2. 软援用(SoftReference):当有足够的内存时,这个援用指向的这个对象就不会被回收,当内存不足时,这块援用指向的对象就会被回收
    3. 弱援用(WeakReference):只有触发GC,这个援用指向的对象就会被回收
    4. 虚援用(PhantomReference):虚援用次要的作用是跟踪垃圾回收的状态,当回收时通过援用队列做一些告诉类的工作【迷迷糊糊,不太了解】
  • 其次咱们来看,为什么要用弱援用指向ThreadLocal对象呢

    • 假如key用的是强援用指向的是ThreadLocal对象,那么当Thread与ThreadLocal之间的援用断掉,又因为ThreadLocalMap是存在于Thread中,只有Thread不隐没,这个ThreadLocalMap就不会隐没,ThreadLocalMap中这个entry就会始终存在从而导致内存透露
    • 当初是key用的弱援用指向的ThreadLocal对象,当Thread与ThreadLocal之间的援用断掉,key与ThreadLocal之间的援用就会主动隐没,不会呈现内存透露的问题
  • 然而ThreadLocal还是会有内存泄露的问题呈现,当ThreadLocal对象被回收,key的值变为了null,导致绝对应的value再也无奈被拜访到,因而还是会呈现内存透露的问题,小伙伴不要把 内存透露 和 内存溢出(OOM)搞混了

    • 内存透露:有一块内存不必了,然而永远无奈被回收
    • 内存溢出(OOM):内存越申请越多,越申请越多,最初内存被占满,无奈再申请到内存了,就会呈现内存溢出OOM

刚刚说ThreadLocal会呈现内存透露,那么会导致内存长期透露吗?

  • 这个是不会的,因为ThreadLocalMap是属于Thread的,只有将Thread销毁,ThreadLocalMap也会跟着被销毁,而且ThreadLocal也有一些“爱护”措施,就是在操作ThreadLocal时,发现key为null时,会将其革除掉,所以大家不必放心会呈现长期性内存透露问题
  • 那么长期性的内存透露是在什么条件下产生的呢,必须要同时满足以下几点才会导致长期性的内存透露

    1. ThreadLocal被回收
    2. 线程复用(线程池的环境下)
    3. 线程复用后不再调用ThreadLocal的set/get/remove办法

说了这么多,那么,你学废了吗?
不点个赞再走嘛