1. ThreadLocal是什么,是用来解决什么问题的?
- ThreadLocal从字面意思来理解,是一个线程本地变量,也可以叫线程本地变量存储。有时候一个对象的变量会被多个线程所访问,这个时候就会有线程安全问题,当然可以使用synchronized关键字来为该变量加锁,进行同步处理来限制只能有一个线程来使用该变量,但是这样会影响程序执行的效率,这时ThreadLocal就派上了用场;
- 使用ThreadLocal维护变量的时候,会为每一个使用该变量的线程提供一个独立的变量副本,即每个线程内部都会有一个当前变量。这样同时有多个线程访问该变量并不会相互影响,因为他们都是使用各自线程存储的变量,所以不会存在线程安全的问题。
- 同步机制采用了“以时间换空间”的方式,而ThreadLocal采用了“以空间换时间”的方式,前者仅提供一份变量,让不同的线程排队访问,而后者为每一个线程都提供了一份变量,因此可以同时访问且互不影响。
2. ThreadLocal源码讲解
源码解析前我们先分析一下ThreadLocal实现原理:每个Thread维护一个ThreadLocalMap映射表,这个映射表的key是ThreadLocal实例本身,value是真正需要存储的Object。也就是说ThreadLocal本身不存储值,它只是作为一个key来让线程从ThreadLocalMap获取value。值得注意的是图中(图片摘自网络)的虚线,表示ThreadLocalMap是使用ThreadLocal的弱引用作为key的,弱引用的对象在GC时会被回收。
- ThreadLocal中有四个主要的方法,如下所示:
public T get() {
} //获取当前线程中ThreadLocal副本
public void set(T value) {
} //用来设置当前线程中ThreadLocal副本
public void remove() {
} //移除当前线程中ThreadLocal副本
protected T initialValue() {
} //是一个protected方法,一般使用时需要重写,默认返回为null
- 详细看一下get()方法的处理逻辑:
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
//获取当前线程
Thread t = Thread.currentThread();
//获取当前线程中的ThreadLocalMap,每个线程都会有一个类型为ThreadLocalMap的inheritableThreadLocals变量
ThreadLocalMap map = getMap(t);
//如果当前线程中ThreadLocalMap为null,则返回初始化值
if (map != null) {
//获取map中ThreadLocal副本
ThreadLocalMap.Entry e = map.getEntry(this);
//获取存储的变量值
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//返回初始化值,一般setInitialValue()需要重写,自定义初始化值
return