ThreadLocal是用来干什么的
ThreadLocal是每个线程自己维护的一个存储对象的数据结构,线程间互不影响实现线程封闭。一般我们通过ThreadLocal对象的get/set方法存取对象。
每个线程都保持对其线程局部变量副本的隐式引用,只要线程是活动的并且ThreadLocal实例是可访问的;在线程消失之后,其线程局部实例的所有副本都会被垃圾回收(除非存在对这些副本的其他引用).
可以总结为一句话: ThreadLocal的作用是提供线程内的局部变量,这种变量在线程的生命周期内起作用,减少同一个线程内多个函数或者组件之前一些公共变量的传递的复杂度。
ThreadLocal源码分析
下面是ThreadLocal类的JDK源码注释:
* This class provides thread-local variables. These variables differ from
* their normal counterparts in that each thread that accesses one (via its
* {@code get} or {@code set} method) has its own, independently initialized
* copy of the variable. {@code ThreadLocal} instances are typically private
* static fields in classes that wish to associate state with a thread (e.g.,
* a user ID or Transaction ID).
*
ThreadLocal使用set方法来保存当前线程的值:
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
/**
* Get the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @return the map
*/
ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}
/**
* Create the map associated with a ThreadLocal. Overridden in
* InheritableThreadLocal.
*
* @param t the current thread
* @param firstValue value for the initial entry of the map
*/
void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}
在set方法中,首先获取到当前的线程对象。由于每个线程对象都是维护了一个ThreadlocalMap对象。所以可以通过线程对象获取到这个map。使用的函数是getMap。如果获取不到就要为当前线程设置ThreadlocalMap对象。设置的key为当前线程。值就是我们保存的值。
再来看get方法
ThreadLocal中的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 map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
return setInitialValue();
}
/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
*
* @return the initial value
*/
private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
protected T initialValue() {
return null;
}
get方法的代码是比较好理解的,还是先获取到线程对象,然后获取线程对象中的ThreadLocalMap,通过这个map的getEntry方法来获取对应值。如果获取失败就不处理。最后执行一个setInitialValue方法。这个方法的主要作用是不管有没有获取成功最后都会向当前的线程对象做这样一个处理:如果当前线程对象没有ThreadLocalMap,那么给它添加一个,初始值为0;这个方法保证了当前线程对象中一定有一个ThreadLocalMap对象。
remove函数用来清除一个ThreadLocal中保存的一个值:
/**
* Removes the current thread's value for this thread-local
* variable. If this thread-local variable is subsequently
* {@linkplain #get read} by the current thread, its value will be
* reinitialized by invoking its {@link #initialValue} method,
* unless its value is {@linkplain #set set} by the current thread
* in the interim. This may result in multiple invocations of the
* {@code initialValue} method in the current thread.
*
* @since 1.5
*/
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
ThreadLocal在实际的项目中的使用很多的。它的作用也很明显。它隔离了线程之间的数据。并且提供给同一线程的不同方法的一个公用的资源库。能够大大提高开发效率。