前言
在阅读前,您需要对ThreadLocal用法有一定了解。如果不了解,请参考ThreadLocal用法相关文章。
子线程如何获取主线程的ThreadLocal里的数据呢?
这个需求或许也很常见,最开始,我们可能会想到InheritableThreadLocal,这是由Jdk为我们提供,他是ThreadLocal的子类,使用方法和ThreadLocal完全相同。
但是这里有几个坑:
1、手动通过线程池创建线程可能会造成get值为null。
2、项目中我们往往会使用线程池,如果主线程使用的是缓存线程池(比如SpringMvc),线程会复用,当线程执行完毕后本次操作后,再次执行新的任务时候,ThreadLocal内部数据并没有被清除。
3、ThreadLocal父子线程之间数据拷贝默认是浅拷贝,这也就意味如果我们多个线程可能会引用同一个内存地址,造成多个线程访问一个对象,轻者会造成线程不安全,重者甚至会ThreadLocal数据被修改成非预期结果。
终级解决方案
这些坑本人亲身体验过,血的教训总结出来,那么如何很好的解决这些问题呢?这边给出一个终级解决方案,使用阿里Transmittable ThreadLocal,可以很好的解决上面这些问题。
具体使用方法可以参见文档:https://github.com/alibaba/transmittable-thread-local
如果使用后发现在缓存线程池下仍然会出现ThreadLocal没有被清理干净的问题,可可尝试重写TransmittableThreadLocal afterExecute方法,在此方法中清除线程数据。
那么通过阿里的TransmittableThreadLocal 如何解决浅拷贝问题呢?这里它提供了一个copy方法,TransmittableThreadLocal 在进行对象拷贝的时候会调用copy方法,我们只需要重写这个方法,让他变量深复制即可。
最后,建议大家不要轻意使用ThreadLocal,能不用尽量不要去使用,一旦在缓存线程池下如果数据没有清理干净会很麻烦,不方便问题排查,而且ThreadLocal有一定情况下会有造成内存泄露的风险,一定要慎用!慎用!慎用!但并不意味着禁用!
网友评论