Struts2的笔记中,在学习关于调用ServletAPI的过程中,我们接触到关于如何获取ActionContext对象,它是通过ThreadLocal设定一个为线程所独享的对象。关于ThreadLocal,我有所疑惑,所以单独列出来探索一下。
ThreadLocal的介绍
ThreadLocal在java.lang包下,译为线程局部变量,它并不是为了解决多线程共享变量而存在的,而是为每个线程创建一个独立的变量副本
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)
大致意思是:该类提供线程局部变量,这些变量不同于通常的副本,它们会在每个线程独立初始化一个属于自己的拷贝,这就保证了即使在多线程的环境下(通过get和set方法),每个线程里的变量依然独立于其他变量。线程局部变量通常是关联线程的静态私有变量,用以关联线程以及线程的上下文。其生命周期和线程生命周期相关。
ThreadLocal显著地降低了一个线程内,多个函数、或者组件访问某个公共变量的复杂度。
ThreadLocal常常应用于按线程多实例的场景,典型应用就是Struts2中的ActionContext,以下是ActionContext源码中的静态属性。
static ThreadLocal<ActionContext> actionContext = new ThreadLocal();
ThreadLocal的操作
ThreadLocal常用的4个方法,分别是:
initialValue()
initialValue():该方法返回局部变量的初始值,这个方法是protected方法,这意味着它能够被子类重写,事实上,它就是用来被子类重写的。这是一个延迟加载方法,只有在线程第一次调用get或者set方法时才执行,并且只执行一次,该方法的缺省返回值为null。
protected T initialValue() {
return null;
}
get()
该方法返回当前线程中的线程局部变量
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();
}
如果当前线程中没有局部变量值,那么就会返回初始值。
set()
用以设定当前线程的局部变量。
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
remove()
public void remove() {
ThreadLocalMap m = getMap(Thread.currentThread());
if (m != null)
m.remove(this);
}
用以删除当前线程中的局部变量。
//TODO