ThreadLocal原理分析

发布于:2022-12-26 ⋅ 阅读:(386) ⋅ 点赞:(0)

公司新来了一位00后java美女程序员,因为年龄太小了,我就叫她幺妹吧。有一天幺妹莫名其妙走到我办公桌旁边,柔情地看着我说:“哥,你知道怎么用ThreadLocal吗?能给我讲讲它的底层实现吗?”,她来得有点突然,问题问得也有点突然,恰好我当时手头上有事正在忙,心里是一千个不愿意,不过程序员都知道,在我们这个行业女同志是很少的,特别是美女同志就更少了,心里一番斗争下来后,还是答应给人家讲讲,毕竟人家是刚入行不久。

“问你个问题,在写web应用的时候,如果用户登录成功了,并且将用户信息存放到了Session中,此时想要在Service层的代码中获取用户信息该怎么办?”我理了理思路,然后问她;

“在Controller类中从Session中获取到用户信息,然后在Service对应的方法上添加参数传递”她想了想然后回答;

“嗯,这个方法是可以实现的,但是如果我所有的Service层代码都需要获取用户信息,那是不是要累死啊,还有,如果有一天这个用户的类名改了,是不是也要改疯?这很显然不是一种好的思路,代码量增加了,还不利于扩展和维护,是吧?”。

“有道理,果然是大神,有没有什么好方法呢?教教我”,她有点着急。

“其实也很简单,只要添加一个拦截器,在拦截器里面定义一个ThreadLocal对象,然后获取用户信息,并将用户信息set到这个ThreadLocal对象中,这样在同一个线程中不管是Service层,或者任何其他类中调用ThreadLocal的get方法就轻松获取到”,我笑着回答。

“这么简单啊,但是为什么调用ThreadLocal的set方法后,在其他地方都可以获取到呢?其中的原理是什么呢?”,她追问。

“好吧,给你讲讲原理”,我打开电脑,写了一段简单的代码,然后分析原理:

要弄懂ThreadLocal的底层实现原理,跟踪set和get方法,

先看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);
}

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

以上流程如下:

1.先是得到当前线程;

2.然后获取线程的threadLocals对象;

3.判断threadLocals对象是否为空,如果为空(没用过当然为空),就调用createMap去创建threadLocals对象,这个threadLocals的类是ThreadLocalMap,这个ThreadLocalMap有点类似HashMap,暂时可以简单的理解为key-value的集合类(后续咱们会单独讲HashMap的原理),其关系如下图所示:

 

4.如果不为空,则直接调用这个map对象的set方法,注意,这里的key是this,value是我们需要设置的值,这个this就是咱们的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) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

这个方法简单,从当前线程的threadLocals这个map对象中获取到key为this对应的value值,注意这里的key也是this。

好,主要原理对应的方法已经分析了,主要思想也就在这里了,一句话总结下:

每个线程中都维护了一个Map对象,set的值就是存放在线程自己的这个Map对象中,而key就是这个ThreadLocal对象,在get的时候也是从每个线程自己的这个Map中去获取的,于是实现了不同线程之间数据的隔离。

 

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到