ThreadLocal是JavaJava标准库提供了一个特殊的上下文神器,目的是为了在单线程执行的时候需经常传递一些相同的参数,比如传递一个状态。
比如传递一个User对象
public void process(User user) { checkPermission(user); doWork(user); saveStatus(user); sendResponse(user); }
为了解决这一繁杂的参数或者对象传递,则需要使用到 ThreadLocal来存储。
它的典型使用方式如下:
static ThreadLocal<User> threadLocalUser = new ThreadLocal<>();
public void processUser(user) { try { threadLocalUser.set(user); step1(); step2(); } finally { threadLocalUser.remove(); } }
常用的手段为:
static ThreadLocal<User> threadLocalUser = new ThreadLocal<>();
注意到普通的方法调用一定是同一个线程执行的,所以,step1()
、step2()
以及log()
方法内,threadLocalUser.get()
获取的User
对象是同一个实例。
实际上,可以把ThreadLocal
看成一个全局Map<Thread, Object>
:每个线程获取ThreadLocal
变量时,总是使用Thread
自身作为key:
Object threadLocalValue = threadLocalMap.get(Thread.currentThread());
是因为当前线程执行完相关代码后,很可能会被重新放入线程池中,如果ThreadLocal
没有被清除,该线程执行其他代码时,会把上一次的状态带进去。
为了保证能释放ThreadLocal
关联的实例,我们可以通过AutoCloseable
接口配合try (resource) {...}
结构,让编译器自动为我们关闭。例如,一个保存了当前用户名的ThreadLocal
可以封装为一个UserContext
对象
public class UserContext implements AutoCloseable { static final ThreadLocal<String> ctx = new ThreadLocal<>(); public UserContext(String user) { ctx.set(user); } public static String currentUser() { return ctx.get(); } @Override public void close() { ctx.remove(); } }