理解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重新赋值以及使用完成后做相应的清理,否则就会出现意想不到的结果。

上一篇下一篇

猜你喜欢

热点阅读