目录
定义:
每个线程new thread()的变量
从名字我们就可以看到ThreadLocal
叫做本地线程变量,意思是说,ThreadLocal
中填充的的是当前线程的变量,该变量对其他线程而言是封闭且隔离的,ThreadLocal
为变量在每个线程中创建了一个副本,这样每个线程都可以访问自己内部的副本变量。
ThreadLocal本质是以线程为key存储元素
ThreadLocal可以把用户信息保存在线程中,用户的每一次请求,就是一个线程,保存了用户信息,方便我们在后续操作获取用户登录信息。
当请求结束,我们会把保存的用户信息清除掉,防止内存泄漏。
使用:
每个用户其实对应都是去找tomcat线程池中的一个线程来完成工作的, 使用完成后再进行回收,既然每个请求都是独立的,所以在每个用户去访问我们的工程时,我们可以使用threadlocal来做到线程隔离,每个线程操作自己的一份数据
使用ThreadLocal替代Session的好处:
可以在同一线程中很方便的获取用户信息,不需要频繁的传递session对象。
请求和线程的对应关系
tomcat会维护一个线程池,每一个http请求都会从线程池取出一个空闲线程
Tips:一般来说,一个http请求是一个线程,所以每次新请求来都是新线程,都得新保存到threadLocal,且最好每次请求结束删除ThreadLocal的用户信息
但是:如果请求结束不删除threadLocal用户信息化的话,线程池偶尔会导致不同的请求获取到了相同的 ThreadLocal 值。即一个新请求还没登陆就拿到了别人的用户信息
原因:因为在项目中使用了线程池,一个线程会在线程池不断工作,做完了请求1还要做请求2,如果做完请求1没有删除线程变量,那么请求2就会拿到请求1的变量
具体实现流程:
在登录业务代码中,当用户登录成功时,生成一个登录凭证存储到redis中,将凭证中的字符串保存在cookie中返回给客户端。
使用一个拦截器拦截请求,从cookie中获取凭证字符串与redis中的凭证进行匹配,获取用户信息,将用户信息存储到ThreadLocal中,在本次请求中持有用户信息,即可在后续操作中使用到用户信息。
而如何使用ThreadLocal
写一个UserHoder管理ThreadLocal的UserDTO(不用User为了节省空间)
所有属性方法都是static,这样就可以在任意Controller中直接用以下代码
User user = UserHoder.getUser();