早在JDK 1.2的版本中就提供java.lang.ThreadLocal,ThreadLocal为解决多线程程序的并发问题提供了一种新的思路,下面就根据作者的理解来讨论一下它的用法。
首先,从名字上看,ThreadLocal肯定是跟Thread相关的,确实,咱们去看Thread源码就可以看这样一个成员变量:
ThreadLocal.ThreadLocalMap threadLocals = null;
其中ThreadLocalMap中这样定义了一个entry:
static class Entry extends WeakReference> {
/** The value associated with this ThreadLocal. */
Object value;
Entry(ThreadLocal k, Object v) {
super(k);
value = v;
}
}
通过源码咱们可以不必深究,把ThreadLocalMap看成是ThreadLocal对象为key,Object为值的map就行。
然后重点来了, ThreadLocal里面最重要的2个方法:
/**
* 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();
}
/**
* 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);
}
}可以看出,ThreadLocal的set方法是把一个对象直接绑定在当前线程的 ThreadLocalMap中,然后通过get方法拿取 ,这样只要在当前线程没有执行完的情况下,保存在ThreadLocalMap中的对象可以随时通过ThreadLocal作为key拿取。
而不同的线程中的ThreadLocalMap是互不干扰的。说简单点就是将一个对象绑定在当前线程上,只要当前线程有效,这个对象就会一直有效。根据其特性,咱们就可以利用它实现类似session的功能。
首先在拦截中验证链接的合法性,拿到用户的信息,通过ThreadLocal保存,那么在后续程序中就可以直接通过ThreadLocal拿到用户信息了,上代码:
public class UserSession {
private static final ThreadLocal<UserInfo> session= new ThreadLocal<>();
public static void clear () {
session.remove();
}
public static void addUserInfo(UserInfo userInfo) {
UserSession.clear();
session.set(userInfo);
}
public static UserInfo getUserInfo() {
return session.get();
}
}
这样在拦截器中UserSession.addUserInfo(userInfo)保存用户信息,在Controller中任何地方就可以通过UserSession.getUserInfo()获得用户信息了




