前些日子遇到一个需求,要在消息列表对之前版本的做消息详情的兼容,做兼容很简单,无非就是获取版本号做一个不同的实现。但是恶心的是需要把这个版本号一层一层的从方法里传递进来,其实看之前所有的兼容,都是在最初的方法中后续增加appVersion来实现兼容功能,那有没有什么办法可以实现不通过传递参数也能获取到版本号呢?直到遇到了threadLocal
——什么是ThreadLocal?
jdk中是这么解释的
意思大概是ThreadLocal提供线程内的局部变量,这些变量在多线程访问时能保证各个线程中的变量相对独立于于其他线程中的变量。ThreadLocal实例通常来说是private static类型的,用来关联线程和线程的上下文。
总结一下呢,就是它提供线程内的局部变量,在本线程里即取即用,可以减少函数里公共变量传递的复杂度。
——举个
既然把threadLocal写的这么神奇,我们不妨来试一试吧
首先我们先定义一个threadLocal,并给予初始值
之后我们定义线程,并对这些线程进行加法操作
输出结果
从结果中我们可以看到,各个线程之间的值时相互隔离的
——原理
那threadLocal的内部实现是怎么样的呢?
这里我们要了解一下threadLocal的三个方法,也是我们主要用到的三个方法:
public T get()
get方法:获取当前threadLocal的值,如果没有则返回默认值
public void set(T value)
set 方法:用来设置当前threadLocal的值
public void remove()
remove方法:用来删除当前threadLocal的值
我们来看看get方法
首先获取当前线程,再通过当前线程获取threadLocalMap
在getMap方法中,我们发现获取到的是当前线程的一个成员变量threadsLocals
这个threadLocals其实就是threadLocalMap,是threadLocal的一个内部类
而在threadLocalMap中,我们可以看到,它继承了弱引用,用treadLocal作为key,用户需要传递的副本变量作为value
继续来看setInitialValue方法
很直观的可以看到,当map不为空时,设置键值对,当value为空时,则去新建一个map
其实从一个get方法中,我们就大概明白了threadLocal的原理
每个线程都有一个 threadLocal.threadLocalMap 类型的成员变量threadLocals,这个threadLocals就是用来存储我们需要传递的变量,key为当前的threadLocal,value为变量;
开始时,用set方法对thread中的threadLocals初始化,当前hreadLocal变量为键值,以ThreadLocal要保存的副本变量为value,存到threadLocals;当需要使用时,就可以通过get方法获取到变量,当然这个前提是在同一个线程中。
——小结
注意,划重点啦!~
1.每个threadLocal创建的变量其实是存储在每个线程自己的threadLocals中
2.为什么要用threadLocal作为key而不用每个线程的id呢?因为一个线程中是可以有多个threadLocal的,如果用线程id作为key,那就不知道如何区分放进threadLocals的value啦
3.在没有重写setInitValue前提下,要先set再get,默认的值为null会导致空指针哦