今天遇到一个问题,通过Threadlocal获取UserUtil里面的信息
public class UserUtil {
private static ThreadLocal<UserDO> currentUsers = new ThreadLocal<>();
public static void setUser(UserDO userDO) {
currentUsers.set(userDO);
}
public static void remove() {
currentUsers.remove();
}
public static UserDO getUser() {
return currentUsers.get();
}
public static Integer getUserId() {
UserDO userDO = currentUsers.get();
if (userDO != null) {
return userDO.getId();
}
return null;
}
public static String getUsername() {
UserDO userDO = currentUsers.get();
if (userDO != null) {
return userDO.getUsername();
}
return null;
}
}
这个在单线程条件下用起来没有问题,但是如果在这个线程里面开了一个线程池 ,然后执行其他方法;那么线程池里面执行的方法就获取不到user的信息了,原因很简单就是线程换了就拿不到之前的currentUsers这个对象了,此时是null;
解决的方法就是当成参数传进去
Integer userId = UserUtil.getUserId();
String userName = UserUtil.getUsername();
insertCaseExecutor.execute(() -> insertOrUpdateCase(fileName, companyId, finalMapToCallCaseDTO, userId, userName));
之后看了一下tl 记录一下
每一个线程创建的时候都有一个属性
/* ThreadLocal values pertaining to this thread. This map is maintained
* by the ThreadLocal class. */
ThreadLocal.ThreadLocalMap threadLocals = null;
这个是Thread类中的属性
这个ThreadLocalMap 是ThreadLocal的内部静态类
static class ThreadLocalMap {
...
}
也就是说每一个线程都创建了一个ThreadLocalMap 这个类
tl 所谓的k-v不是这个map,而是这个类里面的一个entry entry把k-v封装起来放到一个数组里面
Entry(ThreadLocal<?> k, Object v) {
super(k);
value = v;
}
private Entry[] table;
这里面可以看出来key是threadlocal value是真正你要存的值
这里有一个要注意的是key是tl本身 而不是线程 ,如果理解成了线程才是真的理解反了
每个线程里面只要创建了tl 就把本身当成key放进去,value就是要存的
比如上边的userutil 要存的都是从token里面解析出来的, currentUsers就是key UserDO就是value
比如从token里面解析出来cookie 也可以再建一个currentCookie 的tl 然后把它放进去
这之后map里面的table这个array里面就有两个k-v了
public void set(T value) {
Thread t = Thread.currentThread();
//getMap其中的t不是key而是用当前线程获取它的ThreadLocalMap这个类
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}
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();
}
遗留问题 为什么会内存泄漏 remove方法