ThreadLocal对于每一位Java读者而言我想可能都不陌生,因为面试基本都会被问到。

Java-ThreadLocal三种使用场景

关于ThreadLocal

JDK1.2的版本中就提供java.lang.ThreadLocal类,每一个ThreadLocal能够放一个线程级别的变量, 它本身能够被多个线程共享使用,并且又能够达到线程安全的目的,且绝对线程安全。

ThreadLocal包含了四个方法:

void set(Object value)设置当前线程的线程局部变量的值。public Object get()该方法返回当前线程所对应的线程局部变量。public void remove()将当前线程局部变量的值删除,其目的是为了减少内存使用,加快内存回收。protected Object initialValue()返回该线程局部变量的初始值,该方法是一个protected的方法,目的是为了让子类覆盖而设计的。

在实际的工作中,我们在哪些场景下会用到ThreadLocal呢?这里笔者整理了三个使用场景。

场景一:代替参数的显式传递

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

​但是如果我们将参数存入ThreadLocal中,那么就不用显式的传递参数了,而是只需要ThreadLocal中获取即可。

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

场景二:全局存储用户信息

在现在的系统设计中,前后端分离已基本成为常态,分离之后如何获取用户信息就成了一件麻烦事,通常在用户登录后, 用户信息会保存在Session或者Token中。 这个时候,我们如果使用常规的手段去获取用户信息会很费劲,拿Session来说,我们要在接口参数中加上HttpServletRequest对象,然后调用 getSession方法,且每一个需要用户信息的接口都要加上这个参数,才能获取Session,这样实现就很麻烦了。

在实际的系统设计中,我们肯定不会采用上面所说的这种方式,而是使用ThreadLocal,我们会选择在拦截器的业务中, 获取到保存的用户信息,然后存入ThreadLocal,那么当前线程在任何地方如果需要拿到用户信息都可以使用ThreadLocal的get()方法 (异步程序中ThreadLocal是不可靠的)

对于笔者而言,这个场景使用的比较多,当用户登录后,会将用户信息存入Token中返回前端,当用户调用需要授权的接口时,需要在header中携带 Token,然后拦截器中解析Token,获取用户信息,调用自定义的类(AuthNHolder)存入ThreadLocal中,当请求结束的时候,将ThreadLocal存储数据清空, 中间的过程无需在关注如何获取用户信息,只需要使用工具类的get方法即可。

public class AuthNHolder {private static final ThreadLocal> loginThreadLocal = new ThreadLocal>();public static void map(Map map){loginThreadLocal.set(map);}public static String userId(){ return get("userId");}public static String get(String key){ Map map = getMap(); return map.get(key); }public static void clear(){ loginThreadLocal.remove();}}

场景三:解决线程安全问题

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

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

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

慎用的场景

1.线程池中线程调用使用ThreadLocal 由于线程池中对线程管理都是採用线程复用的方法。在线程池中线程非常难结束甚至于永远不会结束。 这将意味着线程持续的时间将不可预測,甚至与JVM的生命周期一致

2.异步程序中,ThreadLocal的參数传递是不靠谱的, 由于线程将请求发送后。就不再等待远程返回结果继续向下运行了,真正的返回结果得到后,处理的线程可能是其他的线程。Java8中的并发流也要考虑这种情况

3.使用完ThreadLocal ,最好手动调用 remove() 方法,防止出现内存溢出,因为中使用的key为ThreadLocal的弱引用, 如果ThreadLocal 没有被外部强引用的情况下,在垃圾回收的时候会被清理掉的,但是如果value是强引用,不会被清理, 这样一来就会出现 key 为 null 的 value。

java get请求传参_Java-ThreadLocal三种使用场景相关推荐

  1. java持久层用文件_JAVA中用三种方法将字符串持久化到文件中

    经常需要将数据进行持久化,而我们的文件系统是最古老也是最可靠的保存方式.这里就给出一个在JAVA中把字符串保存到文件中的例子.如下: package test.base; import java.io ...

  2. java 运行class 传参_JAVA 不同Class传值问题

    展开全部 可以通过构62616964757a686964616fe4b893e5b19e31333365663431造方法传递给 B, 如下:import java.awt.*; import jav ...

  3. java调用c传参_JAVA 调用C 语言程序,并且进行传参收结果等操作

    import java.io.*; import java.lang.*; class test3{ public static void main(String []args) throws IOE ...

  4. java循环嵌套语句示范_java的三种循环结构与循环嵌套

    循环结构: 语法,及执行顺序 语法: while(boolean类型){ //功能语句 } 执行顺序: 1断小括号中的值是否为true,如果为true,执行功能语句 2行完功能语句,继续判断小括号中的 ...

  5. shell脚本触发java程序支持传参补跑_01

    文章目录 一.java程序 1. 创建java项目 2. 创建包结构 3. 创建java类 4. 编译 5. 编译后的包结构总览 二.shell脚本 2.1. 创建基础目录 2.2. 上传项目到指定目 ...

  6. C语言与java中函数传参比较

    C语言与java中函数传参比较 首先先说结论:C语言中参数传递有值传递,地址传递,引用传递.但java中的参数传递只有值传递 1.C语言中的参数传递 1>值传递 值传递非常好理解,其实就是对函数 ...

  7. scrapy实现post请求与请求传参

    不推荐使用scrapy框架发送post请求,配置复杂,如果在数据量大 的情况下,可以通过如下代码来实现: import scrapyclass FySpider(scrapy.Spider):name ...

  8. 18-爬虫之scrapy框架请求传参实现的深度爬取(全站爬取)05

    请求传参实现的深度爬取 深度爬取:爬取的数据没有在同一张页面中(首页数据+详情页数据) 在scrapy中如果没有请求传参我们是无法进行持久化存储数据的 实现方式: scrapy.Request(url ...

  9. 爬虫开发10.scrapy框架之日志等级和请求传参

    今日概要 日志等级 请求传参 今日详情 一.Scrapy的日志等级 - 在使用scrapy crawl spiderFileName运行程序时,在终端里打印输出的就是scrapy的日志信息. - 日志 ...

最新文章

  1. Udacity机器人软件工程师课程笔记(三十六) - GraphSLAM
  2. WebAssembly Studio:Mozilla提供的WASM工具
  3. iOS学习笔记2-微博cell界面的实现
  4. 在ubuntu中安装minicom时出现device /dev/tty8 is locked解决办法
  5. JavaScript浮点运算0.2+0.1 !== 0.3
  6. C/C++中预编译#,##,#error作用
  7. 无线 iphone客户端测试白皮书(二)
  8. 为Eclipse安装功能扩展插件
  9. JS中浮点数运算误差处理
  10. Webpack 2 视频教程 009 - 配置 ESLint 实现代码规范自动测试 (上)
  11. 93. 复原IP地址
  12. 抓包工具——【Mac】Charles的下载和安装
  13. JAVA调用海康威视SDK
  14. 虚拟化试题1-网络和存储
  15. Sketch 54.1 Shark 鲨鱼中文汉化特别版 Mac 设计师必备的原型UI设计工具
  16. 目标检测经典论文——YOLOv3论文翻译:YOLOv3: An Incremental Improvement(YOLOv3:增量式的改进)
  17. NOIP 2006 金明的预算方案 (裸?)分组背包
  18. ddr2代内存最大升级到多少_DDR2台式内存条单条最大多少G?
  19. 《Mysql必知必会》-----笔记(2)
  20. 对List进行多维度排序

热门文章

  1. Nginx常见的错误及解决方法
  2. alibaba面试题
  3. 前端:jQuery对象和dom对象的转换
  4. react-antd项目中重新npm  install  导致自动升级antd版本,引发的样式问题
  5. 基于Vuejs+ElementUI的答案录入功能的一些总结
  6. USB学习笔记连载(八):FX2替换到FX2LP需要注意事项
  7. ffmpeg+ffserver搭建流媒体服务器
  8. 如何检查linux系统的负载高低
  9. Mocha BSM 6.8成功发布
  10. 在自行车论坛看到的有趣帖子