关于项目中使用ThreadLocal来存储Session

前言

在各种Session 管理方案中, ThreadLocal 模式得到了大量使用。ThreadLocal 是Java中一种较为特殊的线程绑定机制。通过ThreadLocal存取的数据,总是与当前线程相关,也就是说,JVM 为每个运行的线程,绑定了私有的本地实例存取空间,从而为多线程环境常出现的并发访问问题提供了一种隔离机制。

首先,我们需要知道,SessionFactory负责创建Session,SessionFactory是线程安全的,多个并发线程可以同时访问一个SessionFactory 并从中获取Session 实例。而Session并非线程安全,也就是说,如果多个线程同时使用一个Session实例进行数据存取,则将会导致Session 数据存取逻辑混乱。

Session对象

Session是服务器端技术,利用这个技术,服务器可以把与会话相关的数据写到一个代表会话的 Session对象中,用来存储用户跨网页程序的变量或对象,只针对单一用户。

Session用于保存每个用户的专用信息。她的生存期是用户持续请求时间再加上一段时间(一般是20分钟左右)。Session中的信息保存在Web服务器内容中,保存的数据量可大可小。当Session超时或被关闭时将自动释放保存的数据信息。由于用户停止使用应用程序后它仍然在内存中保持一段时间,因此使用Session对象使保存用户数据的方法效率很低。对于小量的数据,使用Session对象保存还是一个不错的选择,Session有效期可以自己设置

1
2
HttpSession session  = request.getSession();
session.setMaxInactiveInterval(“自己想要设置的具体时间”)。

ThreadLocal

ThreadLocal用于保存某个线程共享变量:对于同一个static ThreadLocal,不同线程只能从中get,set,remove自己的变量,而不会影响其他线程的变量。

ThreadLocal在每个线程中对该变量会创建一个副本,即每个线程内部都会有一个该变量,且在线程内部任何地方都可以使用,线程之间互不影响,这样一来就不存在线程安全问题,也不会严重影响程序执行性能。

但是要注意,虽然ThreadLocal能够解决上面说的问题,但是由于在每个线程中都创建了副本,所以要考虑它对资源的消耗,比如内存的占用会比不使用ThreadLocal要大。

ThreadLocal类提供的几个方法:

  • ThreadLocal.get: 获取ThreadLocal中当前线程共享变量的值,获取ThreadLocal在当前线程中保存的变量副本

  • ThreadLocal.set: 设置ThreadLocal中当前线程共享变量的值,设置当前线程中变量的副本

  • ThreadLocal.remove: 移除ThreadLocal中当前线程共享变量的值。

  • ThreadLocal.initialValue: ThreadLocal没有被当前线程赋值时或当前线程刚调用remove方法后调用get方法,返回此方法值,是一个protected方法,一般是用来在使用时进行重写的,它是一个延迟加载方法

为什么会出现用ThreadLocal存储Session的操作?

  • 一方面:我们在会话里存的是用户的登录凭证,而不是用户信息本身。我们可以通过拦截器,在请求开始将凭证置换成用户信息。为了便于在本次请求的后续部分获取到登录用户,所以我通过 ThreadLocal ,将其与当前线程绑定。那么问题来了,request 对象就是本次请求,我们可以在请求结束前的任意时刻,从 request 对象里获取与本次请求有关的数据。实际上,确实可以通过 request 来持有用户数据的。但是从设计上、代码分层上来说,这样不好。在 Spring MVC 框架中, request 是一个比较底层的数据对象,一般我们不直接使用它,看看你处理请求的代码就知道了。而且并不是任意的位置都方便获取 request 对象,因为它不被容器管理,不是随便就能注入给一个 Bean 的。因为不鼓励这样做,requerst 是表现层的对象,要是随便注入,你很可能会将其注入给 service,从而产生耦合。所以,我们自己写一个组件,单独解决这个问题。原则上可以,但事实上不会,这是从代码合理性角度考量的。
  • 另一方面:可以实现Session AnyWhere
  • 另一方面:线程安全,不会出现对同一Session对象操作造成的并发问题
文章作者: GeYu
文章链接: https://nuistgy.github.io/2023/03/20/关于ThreadLocal和Session/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yu's Blog