详解 ThreadLocal
ThreadLocal 是什么
ThreadLocal 类提供了一种线程本地变量的实现方式。不同于各线程都可以访问的全局变量,ThreadLocal 中的变量属于线程私有,只有当前线程才能访问到。
ThreadLocal 能做什么
案例:为每个线程生成唯一的标识符;第一次调用 ThreadId.get()时会返线程 Id 会被赋值。当第一次调用 get 方法时会触发 initialValue 生成初始值。
上面的案例可以衍生出其他适用场景,比如登录 token 信息的传递等等。
ThreadLocal 是怎么实现线程本地变量的
想必大家看到这,内心中还是存在疑问,为什么 ThreadLocal 能够实现线程的本地变量?数据是怎么存储的?那么先上图说明其存储结构和实现本地变量的原理,然后再通过关键方法的源码解析去支撑和印证我们的说法。
从图中我们可以看到
每个线程持有一个 ThreadLocalMap 的对象。
ThreadLocalMap 内部有个数组,数组对象是 Entry。
Entry 的 key 是 ThreadLocal 对象,value 是我们设置的具体值。
通过每个线程自己持有一个单独的 ThreadLocalMap 对象,并向这个对象中设置对应的 value 值,实现了线程私有的本地变量设置和获取。
接下来我们通过源码来看下本地变量的设置、获取、删除方法。
set(T value)
set 方法通过获取当前线程的 ThreadLocalMap 对象并以 ThreadLocal 为 key,设置的值为 value 向其设值。ThreadLocalMap 大家可以简单的理解成为一个 map,由于不是本文重点解释内容,ThreadlocalMap 详细的细节,感兴趣的小伙伴可以自行查阅源码。
get()
get 方法是获取到当前线程的 ThreadLocalMap 对象,然后去对应的值。如果获取到的 ThreadLocalMap 值是 null 则 initialValue() 返回的值设置到 ThreadLocalMap 中并返回。
remove()
获取到当前线程的 ThreadLocalMap 值,并删除对应的值。
ThreadLocal 使用注意点
避免读取到脏数据
现在代码中比较常见的使用到了线程池,线程池中的线程是可重复利用的,假设使用 ThreadLocal 设置了 value 值,如果没有进行 remove 操作,下次改线程又被取到,通过 get 方法取到的值是上次设置的 value 值。
处理方式:使用完后进行 remove 操作。
避免内存泄漏
使用了线程池后,由于线程一直存在,对应的 value 值就不能被垃圾回收掉,容易产生内存泄漏问题。
处理方式:使用完后进行 remove 操作。
版权声明: 本文为 InfoQ 作者【threedayman】的原创文章。
原文链接:【http://xie.infoq.cn/article/b797bda7158a7516d0cc38902】。
本文遵守【CC-BY 4.0】协议,转载请保留原文出处及本版权声明。
评论