2022-03-02 ThreadLocal运行机制

今天遇到一个问题,通过Threadlocal获取UserUtil里面的信息

public class UserUtil {
    private static ThreadLocal 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方法

你可能感兴趣的:(2022-03-02 ThreadLocal运行机制)