1.概述
ThreadLoca称线程局部变量,用于在线程中保存数据,保存的数据仅属于当前线程(即对其他线程而言,该变量是当前线程独有的变量)
threadLocal利用Thread中的ThreadLocalMap来进行数据存储
2.常用方法
-
存储数据至当前线程ThreadLocalMap中:public void set(T value)
-
从当前线程的ThreadLocalMap中删除数据,public void remove()
3.ThreadLocalMap内部结构
一个Entry类型的数组,每个Entry对象的key为ThreadLocal对象,value为存储的数据
4.为什么用ThreadLocal作key
线程中可能不只使用了一个ThreadLocal对象,如果这时使用了Thread作key的话,就容易出现混淆
故使用ThreadLocal作key,通过具体的ThreadLocal的get()方法,获取到当前线程的ThreadLocalMap,进一步获得对应的Entry数组。
5.ThreadLocalMap如何查找数据
ThreadLocalMap底层通过Entry[]数组保存key-value,当通过ThreadLocal的get()、set()、remove()等方法时,访问ThreadLocalMap时,最终都会通过一个下标,来完成对数组中的元素访问。
int i=key.threadLocalHashcode&(len-1);
/**
通过Key的“HashCode值”跟“数组的长度减1”做“&按位与”运算.其中Key就是ThreadLocal对象。这种计算方式,
相当于用“hashcode”跟“数组的长度”进行“%取余”运算.
假设:len=16key, threadLocalHashCode=31
hash & hash-1 的计算结果与hash%len的计算结果一致,均为15,但是
“&按位与”运算的效率更高。
**/
6.父子线程如何共享数据
在这种情况下使用ThreadLocal是行不通的。
主方法是在主线程中执行的,相当于父线程.在Main方法中开启了另外一个线程,相当于子线程.两个线程对象,各自拥有不同的ThreadLocalMap。
应该使用InheritableThreadLocal,它继承了ThreadLocal类
7.ThreadLocal如何避免内存泄露
使用完毕后,在finally调用ThreadLocal对象的remove()方法
remove方法会把Entry中的key和value都设置为null,这样就可以及时被GC回收,无需触发额外的清理机制,能够解决内存泄露问题。
8.ThreadLocal应用场景
1.线程数据隔离:ThreadLocal中的数据只属于当前线程的,该数据对别的线程是不可见的,起到隔离作用,避免了同步加锁带来的性能损失。
2.跨函数传递:降低了类或方法之间的耦合度,在同一个线程内,跨类、跨方法传递数据时,不必靠返回值和参数