TransmittableThreadLocal简单了解
1、如何解决单线程程序运行中变量共享问题?
借助ThreadLocal可以做到,在单线程程序运行的任意地方都可以获取变量,这个对象叫线成的本地变量。
想要了解线成内变量共享的原理,就得看一下线成内部结构:
- 线程Thread类中维护着ThreadLocalMap对象;
- ThreadLocalMap中的Entry继承自WeakReference
- Entry的key为被WeakReference包装的ThreadLocal对象
- ThreadLocal对象的get\set操作的底层都是处理当前Thread所拥有的ThreadLocalMap对象
网上找了个比较形象的图:
2、多个线程的情况下,为什么InheritableThreadLocal可以解决线程本地变量父传子问题?
InheritableThreadLocal继承自ThreadLocal类,特殊性就体现在他的getMap方法:
1 | ThreadLocalMap getMap(Thread t) { |
这里引出了线成对象的inheritableThreadLocals属性,含义就是可继承的ThreadLocalMap。那么为什么说它是可继承的呢?
通过Thread类阅读源码得知:
创建Thread对象时,会调用其init方法,其中涉及到可继承线程本地变量的代码:
1 | this.inheritableThreadLocals =ThreadLocal.createInheritedMap(parent.inheritableThreadLocals); |
核心:将父线程的线程变量的引用复制一份,放到子线程维护的inheritableThreadLocals中。
这里发现两个问题:
- 传递的是引用,子线程修改线程变量值会影响到父线程,发生上下文污染问题。
在业务处理过程中,子线程尽量只读程变量值,不要写入。
- 只有新创建Thread对象才会传递线程变量
线程池化技术应用时,会复用线程,此时线程变量传递方法不会被触发。
在业务开发过程中,我们大多会用线程池来做一些异步处理逻辑,涉及到传递主线程的线程变量,此时用InheritableThreadLocal就有些力不从心。引出:阿里的TransmittableThreadLocal。
3、为什么TransmittableThreadLocal就可以解决InheritableThreadLocal复用线程时,线程变量传递的问题呢?
先来一张结构图:
TransmittableThreadLocal继承InheritableThreadLocal,也就是说,新建线程时,线程变量会发生传递。
重点看holder属性:
1 | // Note about holder: |
- holder 是 InheritableThreadLocal变量
- holder 是 static 变量
- value 是 WeakHashMap
参考文档:
https://github.com/alibaba/transmittable-thread-local
https://www.cnblogs.com/hama1993/p/10382523.html
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 ClawHub的技术分享!