关于java:多线程高并发学习之ThreadLocal

3次阅读

共计 1962 个字符,预计需要花费 5 分钟才能阅读完成。

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 办法

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

正文完
 0