本文大纲
- 用过ThreadLocal吗?在什么场景下会使用ThreadLocal
- 讲讲ThreadLocal的原理吧!
- 使用ThreadLocal有什么需要注意的吗?
- 有什么方式能提高ThreadLocal的性能吗?
- 如何将ThreadLocal的数据传递到子线程中?
- 线程池中如何实现ThreadLocal的数据传递?
用过ThreadLocal吗?在什么场景下会使用ThreadLocal。
这个回答一定要足够自信:必须用过啊,无论是在平时的业务开发过程中会用到,其他很多三方框架中也都用到了ThreadLocal。
如果你回答没用过,很有可能就凉凉了,因为ThreadLocal在很多场景都能用到,假如实在没用过也不要没信心,看完这篇文章你就知道如何回答了。
场景一:ThreadLocal+MDC实现链路日志增强
日志增强之前也写过一篇文章,讲解了实现的功能,细节没有讲,可以看看下面这篇文章了解。
比如我们需要在整个链路的日志中输出当前登录的用户ID,首先就得在拦截器获取过滤器中获取用户ID,然后将用户ID进行存储到ThreadLocal。
然后再层层进行透传,如果用的Dubbo,那么就在Dubbo的Filter中进行传递到下一个服务中。问题来了,在Dubbo的Filter中如何获取前面存储的用户ID呢?
答案就是ThreadLocal。获取后添加到MDC中,就可以在日志中输出用户ID。
场景二:ThreadLocal实现线程内的缓存,避免重复调用
缓存这块就不重复讲了,之前有单独写过文章,大家直接看之前的文章就可以了。
场景三:ThreadLocal实现数据库读写分离下强制读主库
首先你的项目中要做了读写分离,如果有对读写分离不了解的同学可以查看这篇文章:读写分离
某些业务场景下,必须保证数据的及时性。主从同步有延迟,可以使用强制读主库来保证数据的一致性。
在Sharding JDBC中,有提供对应的API来设置强制路由到主库,具体代码如下:
HintManager hintManager = HintManager.getInstance();
hintManager.setMasterRouteOnly();
HintManager中就使用了ThreadLocal来存储相关信息。这样就可以实现在业务代码中设置路由信息,在底层的数据库路由那块获取信息,实现优雅的数据传递。
public final class HintManager implements AutoCloseable {
private static final ThreadLocal<HintManager> HINT_MANAGER_HOLDER = new ThreadLocal();
// ...............
}
场景四:ThreadLocal实现同一线程下多个类之间的数据传递
在Spring Cloud Zuul中,过滤器是必须要用的。用过滤器我们可以实现权限认证,日志记录,限流等功能。
过滤器有多个,而且是按顺序执行的。过滤器之前要透传数据该如何处理?