ThreadLocal概念以及使用场景

根据自身的知识深度,这里只限于自己使用和学习的知识点整理,原理的解释还需要再沉淀。

该文章从项目开发中举例,希望能帮助到各位,不了解ThreadLocal的朋友,可能会问,这是个是什么,这有什么用,这能用在哪些地方,接下来我一一解释,如果有地方解释不好,希望多多包含。

概念:

这是个是什么:

ThreadLocal是一个类,是一个本地线程,提供了一种线程安全的方式,用来避免共享数据(线程变量隔离)。

翻看源码可以看到注释(已翻译):

此类提供线程局部变量。 这些变量不同于它们的普通对应变量,因为每个访问一个(通过其get或set方法)的线程都有自己的、独立初始化的变量副本。 ThreadLocal实例通常是希望将状态与线程相关联的类中的私有静态字段(例如,用户 ID 或事务 ID)

这有什么用:

按照《Java核心卷一》来说,有时候可能要避免共享变量,使用ThreadLocal辅助类为各个线程提供各自的实例;

就是说,每个线程都有一个伴生的空间(ThreadLocal),存储私有的数据。

只要线程存在,就能拿到对应的ThreadLocal中存储的值。

创建以及提供的方法

创建一个线程局部变量,其初始值通过调用给定的提供者(Supplier)生成;

  1. public static <S> ThreadLocal<S> withInitial(Supplier<? extends S> supplier) {
  2. return new SuppliedThreadLocal<>(supplier);
  3. }

使用的方法也比较少:

这里就列出用的比较多的方法:

返回此线程局部变量的当前线程副本中的值。 如果该变量对于当前线程没有值,则首先将其初始化为调用initialValue方法返回的值:

  1. T get()

将此线程局部变量的当前线程副本设置为指定值;

value -- 要存储在此线程本地的当前线程副本中的值

  1. void set(T value)

删除此线程局部变量的当前线程值(删除这里有些讲究,暂且不表,留在后面)

  1. void remove()

项目实例:

ThreadLocal使用的场景主要是:(引用)

每个线程需要自己独立的实例且该实例需要在多个方法中使用

以下是个人使用的场景:

自己为什么会使用它,我是想在项目中直接获取当前用户的信息,这个功能就使用了ThreadLocal;

首先创建一个ThreadLocal类:

  1. import com.xbhog.springbootvueblog.pojo.SysUser;
  2. public class UserThreadLocal {
  3. private UserThreadLocal(){}
  4. private static final ThreadLocal<SysUser> LOCAL = new ThreadLocal<>();
  5. public static void put(SysUser sysUser){
  6. LOCAL.set(sysUser);
  7. }
  8. public static SysUser get(){
  9. return LOCAL.get();
  10. }
  11. public static void remove(){
  12. LOCAL.remove();
  13. }
  14. }

其中包含了数据的添加删除和获取,因为我们需要的是用户信息,那么就把User类传入泛型中;

操作的对象有了,接下来就是使用:

在该项目中个人使用的地方在登录拦截器中,当对登录的信息检查成功后,那么将当前的用户对象加入到ThreadLocal中,

  1. //登录验证成功,放行
  2. System.out.println("走到UserThreadLocal--------");
  3. UserThreadLocal.put(sysUser);

在controller中使用的时候,直接调用ThreadLocal中的get方法,就可以获得当前用户的信息:

  1. //获取当前在线用户信息
  2. SysUser sysUser = UserThreadLocal.get();

资源调用完成后需要在拦截器中删除ThreadLocal资源:

  1. @Override
  2. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
  3. //使用完的用户信息需要删除,防止内存泄露
  4. UserThreadLocal.remove();
  5. }

afterCompletion作用:

实现最终的完成后进行处理,该方法在执行完控制器之后执行,由于是在Controller方法执行完毕后执行该方法,所以该方法适合进行一些资源清理,记录日志信息等处理操作

什么意思呢:

程序首先执行拦截器类中的preHandle()方法,如果该方法返回值是true,则程序会继续向下执行处理器中的方法,否则不再向下执行;在业务控制器类Controller(这里就可以用ThreadLocal 获取用户信息)处理完请求后,会执行postHandle()方法,

而后会通过DispatcherServlet向客户端返回响应;在DispatcherServlet处理完请求后,才会执行afterCompletion()方法(这里删除这次请求的ThreadLocal 中的user信息);

ThreadLocal的内存泄露问题:

如果我们在使用完该线程后不进行ThreadLocal 中的变量进行删除,那么就会造成内存泄漏的问题,那么该问题是怎么出现的?

首先先看一下ThreadLocal 内部结构:

首先对于对象在栈中保存的是对象的引用,对象的存储在堆中,要先明确概念。栈中的格式也符合我们上述我们画的图1,其中Heap中的map是ThreadLocal map,里面包含key和value,其中value就是我们需要保存的变量数据,key则是ThreadLocal实例;

即:每一个Thread维护一个ThreadLocalMap, key为使用弱引用的ThreadLocal实例,value为线程变量的副本。

还需要注意的是上述图片的连接有实线和虚线,实线代表强引用,虚线表示弱引用;

扫盲强引用、软引用、弱引用、虚引用:

  1. 强引用,我们使用的大部分引用都是强引用,特点就是当内存不足时,垃圾回收器宁愿自己抛出OOM,也不会回收强引用来解决内存不足的问题
  2. 软引用,就是生杀大权都在垃圾回收器中,我内存够的话,你可以活着,如果不够的话,我就回收你,给我腾地方;
  3. 弱引用,只要垃圾回收器扫到,不管空间够不够,都给我回收了;
  4. 虚引用,形同虚设的东西,在任何情况下都可能被回收

这里只给出了概念,如果感兴趣可以自行了解作用环境。

那么知道强引用、弱引用后我们再来看图,因为ThreadLocal与线程属于同一个生命周期,当在某一个阶段进行了一次GC,那么当前线程还在,但是ThreadLocal实例被回收了,也就是key没了,

我们都知道,map中的value需要key找到,key没了,那么value就会永远的留在内存中,直到内存满了,导致OOM,所以我们就需要使用完以后进行手动删除,这样能保证不会出现因为GC的原因造成的OOM问题;

参考文献:

ThreadLocal解决了什么问题

SpringMVC---拦截器

写的太细了!Spring MVC拦截器的应用,建议收藏再看!

结束:

如果你看到这里或者正好对你有所帮助,希望能点个或者感谢;

有错误的地方,欢迎在评论指出,作者看到会进行修改。

ThreadLocal概念以及使用场景的更多相关文章

  1. Android线程管理之ThreadLocal理解及应用场景

    前言: 最近在学习总结Android的动画效果,当学到Android属性动画的时候大致看了下源代码,里面的AnimationHandler存取使用了ThreadLocal,激起了我很大的好奇心以及兴趣 ...

  2. MQ(1)---消息队列概念和使用场景

    消息队列概念和使用场景 声明:本文转自:MQ入门总结(一)消息队列概念和使用场景 写的很好,都不用自己在整理了,非常感谢该作者的用心. 一.什么是消息队列 消息即是信息的载体.为了让消息发送者和消息接 ...

  3. kubernetes1.9管中窥豹-CRD概念、使用场景及实例

    欢迎访问网易云社区,了解更多网易技术产品运营经验. 前言 默认读者有kubernetes基础概念的背景知识,因此基础概念例如有状态.pod.Replica Sets.Deployments.state ...

  4. [原创]cocos2d-x研习录-第二阶 概念类之场景类(CCScene)

    场景类CCScene是Cocos2D-x在屏幕显示的内容,相当于游戏关卡或界面.CCDirector任何时候只能显示一个场景CCScene,游戏中可能存在若干场景,CCDirector通过场景切换达到 ...

  5. WCF回顾一、基本概念和应用场景

    一.WCF描述 wcf是一款基于面向服务的架构的通讯框架平台,在分布式框架中得到了广泛使用. wcf入门非常简单,只要花几分钟就能编写一个完整的wcf程序,而实际上WCF是概念非常多的一门技术,需要花 ...

  6. 聊聊ThreadLocal原理以及使用场景-JAVA 8源码

    相信很多人知道ThreadLocal是针对每个线程的,但是其中的原理相信大家不是很清楚,那咱们就一块看一下源码. 首先,我们先看看它的set方法.非常简单,从当前Thread中获取map.那么这个ge ...

  7. ThreadLocal 原理和使用场景分析

    ThreadLocal 不知道大家有没有用过,但至少听说过,今天主要记录一下 ThreadLocal 的原理和使用场景. 使用场景 直接定位到 ThreadLocal 的源码,可以看到源码注释中有很清 ...

  8. [转]RabbitMQ入门教程(概念,应用场景,安装,使用)

    原文地址:https://www.jianshu.com/p/dae5bbed39b1 RabbitMQ 简介 RabbitMQ是一个在AMQP(Advanced Message Queuing Pr ...

  9. redis(redis概念,运用场景,如何操作基本数据类型)

    什么是redis:Nosql一种缓存数据库 redis可以干什么:redis可以减轻对数据库的请求压力如果不使用缓存:客服端->控制层->业务层->dao层使用缓存:客服端-> ...

随机推荐

  1. 你知道 ES6~ES12等叫法是怎么来的吗?

    你知道 ES6~ES12等叫法是怎么来的吗? 前言 作为一名前端开发,学习 JavaScript 自是天经地义的事,但是,JavaScript 的发展历史是怎样的,恐怕有相当一部分人都不太了解. 我们 ...

  2. IDEA常用设置及推荐插件

    IDEA常用设置及推荐插件 本文主要记录IDEA的一些常用设置,IDEA与Eclipse的常用快捷键对比及推荐一些好用的插件. 基本设置 设置界面风格及修改外部UI尺寸大小 打开IDEA时设置不重新打 ...

  3. JDK和环境配置,eclipse安装与使用

    本博客部分参照https://blog.csdn.net/PGY0000/article/details/79256720 (记住要尊重别人的劳动产品) 原博客给的链接和后面的安装过程有点不一样,不能 ...

  4. Python之pyyaml模块

    pyyaml模块在python中用于处理yaml格式数据,主要使用yaml.safe_dump().yaml.safe_load()函数将python值和yaml格式数据相互转换.当然也存在yaml. ...

  5. noip模拟37

    \(\color{white}{\mathbb{燕子来时青尚在,木荫遥看杏花菲,名之以:杏红}}\) 考场发现 \(t2\) 基本上是原题,\(t3\) 的套路见过,\(t4\) 像是并查集之类的算法 ...

  6. Spring Boot 入门系列(二十七)使用Spring Data JPA 自定义查询如此简单,完全不需要写SQL!

    前面讲了Spring Boot 整合Spring Boot JPA,实现JPA 的增.删.改.查的功能.JPA使用非常简单,只需继承JpaRepository ,无需任何数据访问层和sql语句即可实现 ...

  7. Weblogic漏洞分析之JNDI注入-CVE-2020-14645

    Weblogic漏洞分析之JNDI注入-CVE-2020-14645 Oracle七月发布的安全更新中,包含了一个Weblogic的反序列化RCE漏洞,编号CVE-2020-14645,CVS评分9. ...

  8. CommonsBeanutils1 分析笔记

    1.PropertyUtils.getProperty commons-beanutils-1.9.2.jar 包下的 PropertyUtils#getProperty方法相对于getXxx方法,取 ...

  9. C语言学习笔记---3.字符串格式化输入输出

    1.C语言字符串 字符串(character string)是一个或多个字符的序列,例如:"Zing went the strings of my heart!" C语言没有专门用 ...

  10. ecshop不同的文章分类使用不同的模板的方法

    ecshop文章模板做的太简单,页面很丑,怎么才能实现不同的文章使用不同的模板呢,方法是有的,就是没有shopex那么方便,但还可以实现,只要能用就行. 1.打开article_cat.php文件,在 ...