理解ThreadLocal
2019-01-06 本文已影响11人
躁动的中年大叔
ThreadLocal其实可以理解为一个工具类,用来操作线程局部变量。
ThreadLocal为每一个使用该变量的线程都提供一个变量值的副本,使得每一个线程都可以修改自己的变量值副本,而不影响其他线程的变量值。
一、ThreadLocal的使用
1. 创建ThreadLocal实例
1.1 直接创建(指定类型参数)
ThreadLocal tl = new ThreadLocal<Integer>();
1.2 指定初始值的方式创建
// 指定初始值为 1,若不指定则为null
ThreadLocal tl = new ThreadLocal<Integer>(){
@Override
protected Integer initialValue(){
return 1;
}
};
2. 给ThreadLocal实例赋值
// 当前线程的该局部变量的值设为10
tl.set(10);
3. 获取ThreadLocal实例的值
Integer value = tl.get();
二、ThreadLocal的原理
刚接触到ThreadLocal的概念时,可能大多数人都误以为线程的变量值副本都存储在ThreadLocal实例中一个Map结构中,key为线程的标识,value为线程对应的变量值副本。
其实不是这样的,在Thread类里有个threadLocals 的属性,是一个ThreadLocalMap 结构,它将每一个ThreadLocal实例作为key,value为该线程的变量值副本。
即线程的各个局部变量值是存储在线程实例本身中的,ThreadLocal只是获取对应线程局部变量值的标识,也就可以理解为一个工具类了。
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
值得注意的是,ThreadLocalMap 的每一个Entry都是ThreadLocal的一个弱引用(基于JDK1.8),当对应的ThreadLocal实例在失去了强引用,只剩下Entry这个弱引用后将被GC回收,对应的Entry也就为null了,是不存在内存泄漏问题的。
三、ThreadLocal的缺点
其实不应该叫缺点,应该叫使用时需要注意的地方更合适。
我们都知道,线程的创建和销毁都是要付出代价的,日常使用多线程时,包括Tomcat服务器,都是通过线程复用的方式使用多线程,即会使用到线程池。
这种情况下不同的事务请求可能就会复用同一个线程,所以每次使用时要注意为ThreadLocal重新赋值以及使用完成后做相应的清理,否则就会出现意想不到的结果。