再次深入探究ThreadLocal原理及其使用方法,以此记录

再次深入探究ThreadLocal,以此记录。

为什么说ThreadLocal叫做线程本地变量,因为ThreadLocal在每个线程中对该变量会创建一个线程共享变量,即每个线程内部都会有一个该变量,且在线程内部任何地方都可以使用,线程之间互不影响,这样一来就不存在线程安全问题,也不会严重影响程序执行性能。

 

使用ThreadLocal不外乎3个方法:

threadLocal.set()

threadLocal.get()

threadLocal.remove()

顾名思义,分别是设置、获取、移除当前线程中共享变量的值。

话不多说,直接上源码:

get()方法

再次深入探究ThreadLocal原理及其使用方法,以此记录_第1张图片

跟入getMap(t)方法一探究竟

再次深入探究ThreadLocal原理及其使用方法,以此记录_第2张图片

threadLocals

实际上就是一个ThreadLocalMap对象。

ThreadLocalMap其实就是在ThreadLocal中的一个内部类

再次深入探究ThreadLocal原理及其使用方法,以此记录_第3张图片

setInitialValue()

再次深入探究ThreadLocal原理及其使用方法,以此记录_第4张图片

createMap()

再次深入探究ThreadLocal原理及其使用方法,以此记录_第5张图片

new一个ThreadLocalMap对象返回

set()和remove()方法

再次深入探究ThreadLocal原理及其使用方法,以此记录_第6张图片

 

至此,真相大白。

真正存储线程共享变量的地方是当前线程对象Thread的成员变量threadLocals,类型是ThreadLocal.ThreadLocalMap,k:ThreadLocal变量,v:线程共享变量

 

一开始,当前线程中的threadLocals为null,调用set()时,会对其中的threadLocals进行初始化,k就是ThreadLocal,v就是需要存放的线程共享变量

当需要的时候就可以从threadLocals中获取到。

 

总结:

  1. 之所以说ThreadLocal线程安全,是因为所需要存储的线程共享变量,都是存放在当前线程的threadLocals中。
  2. 选择ThreadLocal作为threadLocals的key,是因为每个线程中可有多个threadLocal变量
  3. 在进行get之前,必须先set,否则会报空指针异常;

 

使用ThreadLocal的好处:

  1. 在多线程的环境中,保证当前线程的线程共享变量不被其他线程干扰,即不存在线程安全问题。
  2. 当线程死去时,threadLocals也就被销毁。
  3. threadLocals的k-v数量由ThreadLocal对象的数量决定,比起Thread数量,ThreadLocal数量较少,性能更好。

关于ThreadLocalMap弱引用问题:

当线程没有结束,但是ThreadLocal已经被回收,则可能导致线程中存在threadLocals的键值对,造成内存泄露。

(ThreadLocal被回收,ThreadLocal关联的线程共享变量还存在)。

虽然ThreadLocal的get,set方法可以清除ThreadLocalMap中key为null的value,但是get,set方法在内存泄露后并不会必然调用。

为了防止弱引用问题(threadLocals键值对没有被即使回收,造成内存泄漏)的出现,我们有两种手段:

1、使用完线程共享变量后,显示调用ThreadLocalMap.remove方法清除线程共享变量;

2、JDK建议ThreadLocal定义为private static,这样ThreadLocal的弱引用问题则不存在了。

 

例子为证:

再次深入探究ThreadLocal原理及其使用方法,以此记录_第7张图片

结果:

再次深入探究ThreadLocal原理及其使用方法,以此记录_第8张图片

 

你可能感兴趣的:(再次深入探究ThreadLocal原理及其使用方法,以此记录)