ThreadLocal的常用场景

介绍

threadLocal非常适合在我们的web应用中使用,当web请求进来的时候,我们就可以将一些数据放入到threadLocal中,这样后续所有的相关业务,都可以直接拿到这个值。

常见的就是过滤器,我们在业务中,当小程序的用户发起请求的时候,会将用户的基本信息rpc查询出来后,放入threadLocal,这样方便了后续进行处理。使用完成后,再调用remove进行清除。

一个线程中出现的所有ThreadLocal都是保存在map中的,所以是一个map结构,通过ThreadLocal的key引用来获取值。

场景一(代替参数传递)

当我们在写API接口的时候,通常Controller层会接受来自前端的入参,当这个接口功能比较复杂的时候,可能我们调用的Service层内部还调用了很多其他方法。

通常情况下,我们会在每个调用的方法上加上需要传递的参数。但是如果我们将参数存入ThreadLocal中,那么就不用显式的传递参数了,而是只需要ThreadLocal中获取即可。

这个场景其实使用的比较少,一方面显式传参比较容易理解,另一方面我们可以将多个参数封装为对象去传递。

场景二(解析信息)

用户信息会保存在Session或者Token中。这个时候,我们如果使用常规的手段去获取用户信息会很费劲。

拿Session来说,我们要在接口参数中加上HttpServletRequest对象,然后调用getSession方法,且每一个需要用户信息的接口都要加上这个参数,才能获取Session,这样实现就很麻烦了。

我们需要使用ThreadLocal,我们会选择在拦截器的业务中,获取到保存的用户信息,然后存入ThreadLocal,那么当前线程在任何地方如果需要拿到用户信息都可以使用ThreadLocal的get方法。

当用户登录后,会将用户信息存入Token中返回前端,当用户调用需要授权的接口时,需要在header中携带Token,然后拦载器中解析Token,获取用户信息,调用自定义的类存ThreadLocal中,当请求结束的时候,将ThreadLocal存储数据清空,中间的过程无需在关注如何获取用户信息,只需要使用工具类的get方法即可

场景三(资源分割)

在Spring的Web项目中,我们通常会将业务分为Controller层,Service层,Dao层,我们都知道@Autowired注解默认使用单例模式,那么不同请求线程进来之后,由于Dao层使用单例,负责数据库连接的Connection也只有一个,如果每个请求线程都去连接数据库,那么就会造成线程不安全的问题,Spring是如何解决这个问题的呢?

在Spring项目中Dao层中装配的Connection是线程安全的,其解决方案就是采用ThreadLocal方法,当每个请求线程使用Connection的时候,都会从ThreadLocal获取一次,如果为null,说明没有进行过数据库连接,连接后存入ThreadLocal中,如此一来,每一个请求线程都保存有一份自己的Connection,于是便解决了线程安全问题

ThreadLocal在设计之初就是为解决并发问题而提供一种方案,每个线程维护一份自己的数据,达到线程隔离的效果。

参考资料:【大厂面试题】ThreadLocal的常用场景?

你可能感兴趣的:(Spring,java,开发语言)