ThreadLocal<T> 源码分析 jdk1.6

相信很多做分布式web开发的都封装过这样的一个工具用来管理当前登录的用户。
在拦截器里面把用户set进来
在controller 里面get 出来使用

而且都是基于ThreadLocal 这个模板类来封装的, 出于好奇跟踪进源码一探究竟

注意:由于我所在公司开发使用jdk1.6开发。以下源码为jdk1.6源码,可能与您使用的不一致

这里简单写个例子

public class BaseLoginContext<T extends BaseLoginContext> {
    private final static ThreadLocal<BaseLoginContext> holder = new ThreadLocal<BaseLoginContext>();

    private final static Log log = LogFactory.getLog(BaseLoginContext.class);

    public static void remove() {
        holder.remove();
    }

    public static BaseLoginContext get() {
        return holder.get();
    }

    protected static void set(BaseLoginContext context) {
        holder.set(context);
    }
}
public class LoginContext extends
        BaseLoginContext<LoginContext> {

    private User user = new User();

    public static Long getCurrentUserId() {

        if (getCurrentUser() == null) {
            return null;
        }
        return getCurrentUser().getPk();
    }

    public static boolean isLogin() {
        if (getCurrentUser() == null) {
            return false;
        }
        return getCurrentUserId() > 0;
    }
public static UnionUser getCurrentUser() {
        final UnionMasterLoginContext loginContext = (UnionMasterLoginContext) get();
        if (loginContext == null) {
            return null;
        }
        User user = loginContext.getUser();
        return user;
    }

    public User getUser() {
        return user;
    }
static public void addCurrentUser(User user) {
        LoginContext context = (LoginContext) get();
        if (context == null) {
            set(new LoginContext());
            context = (LoginContext) get();
        }
        context.setUser(user);
    }
    public void setUser(UnionUser user) {
        if (user == null) {
            user = this.user;
        } 
    }

先看一下ThreadLocal的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);
    }

获取当前线程 然后get的到一个ThreadLocalMap,如果不为空就就把当前类(this)作为key要设置的值设置为值。 (这里提一下获取当前线程Thread.currentThread()是java 虚拟机原生实现的源码里可以看到public static native Thread currentThread();使用了native 标记,这表示这个方法我们主管用,原生实现的方法,喜欢的同学可以去找虚拟机源码或者查找jvm规范)

要注意这里key传的是this 当前类对象

至于为什么 我们下面讲述

如果ThreadLocalMap 为空 就调用createMap 创建一个参数为当前线程和要放入的参数。
下面我们先看看 getMap

ThreadLocalMap getMap(Thread t) {
        return t.threadLocals;
}

这里直接返回线程的成员变量threadLocals,在Thread中定义了ThreadLocal.ThreadLocalMap threadLocals = null;
这里看到 ThreadLocalMap 是ThreadLocal的内部类,这个我们可以在ThreadLocal中找到,有点类似与Map 的一个东西,用法也很类似,就理解成一个map也可以 ,这块就不详细说明了, 那么现在我们来看一下createMap

void createMap(Thread t, T firstValue) {
        t.threadLocals = new ThreadLocalMap(this, firstValue);
    }

这里给当前线程创建一个ThreadLocalMap ,

然后和set 里面一样把当前类(this)作为key要设置的值设置为值。

现在我们看一下 ThreadLocal的get

    public T get() {
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null) {
            ThreadLocalMap.Entry e = map.getEntry(this);
            if (e != null)
                return (T)e.value;
        }
        return setInitialValue();
    }

同样也是获取当前线程,然后拿到当前线程的ThreadLocalMap 然后取出key为this 也就是本对象的值。
如果 map 为空 获取一个初始化的值 (其实就是null)
我们可以看一下setInitialValue实现

private T setInitialValue() {
        T value = initialValue();
        Thread t = Thread.currentThread();
        ThreadLocalMap map = getMap(t);
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
        return value;
    }
protected T initialValue() {
        return null;
    }

调用initialValue获取一个默认值 ,其实源码可以看到initialValue什么都没干直接返回null。然后的流程和set 一样 (真好奇这里获取默认值后为什么不直接调用set ,估计是不利于以后改动。万一set变化会影响到)

remove就没什么可说的了很简单

 public void remove() {
         ThreadLocalMap m = getMap(Thread.currentThread());
         if (m != null)
             m.remove(this);
     }

一样的逻辑获取当前线程 ,获取ThreadLocalMap 然后移除本身就可以了;


这里我们讲述一下key传的是this 当前类对象

Thread 中有成员变量ThreadLocalMap threadLocals;是实现ThreadLocal的基础。threadLocals 在每一个线程中都属于线程独自的。
当我们实现一个ThreadLocal ,threadLocals 中就会增加一个键值对。key 就是我们实例化的ThreadLocal,value 就是我们要存储到本地线程的值,key 传this 就把我们实例化的ThreadLocal对象作为键存在threadLocals 中,这样我们实现多个ThreadLocal 的时候 threadLocals 都可以支持,也都能保证ThreadLocal 取到的是自己存放的值。

(刚开始写博客,文字表达能力有限,正在努力学习,请多多见谅)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值