用ThreadLocal来优化下代码吧

用ThreadLocal来优化下代码吧

最近接手了一个老项目,看到一个很有意思的现象。

这个项目中大量的方法入参都会带上user信息,比如这样

用ThreadLocal来优化下代码吧

 

它的意图是希望在方法内使用user的信息,但是如此大范围的传递用户信息,第一感觉就是不优雅。那有什么办法可以优化一下呢?

用ThreadLocal来优化下代码吧

 

我们第一反应是,可以存一个全局变量,在初始位置将用户信息存入全局变量,然后在需要的地方去get一下。

那在WEB应用中,每个请求都是一个独立线程,怎么去标记呢?

可以用线程的id去作为map的key,将该请求的用户信息作为map的value。

咦?很熟悉的感觉。

用ThreadLocal来优化下代码吧

 

没错,Java已经帮我们封装好了这么一个对象,它就是我们今天要说的ThreadLocal。

  • 什么是ThreadLocal
  • 如何使用ThreadLocal优化userid层层传递的问题
  • ThreadLocal原理是啥
  • ThreadLocal的其他使用场景

1.什么是ThreadLocal

先来看下JDK的注释:

用ThreadLocal来优化下代码吧

 

简单翻译过来,就是说:

ThreadLocal提供了线程隔离的局部变量,通过get( )和set( )方法操作当前线程对应的变量,而且不会和其他线程冲突,实现了基于线程的数据隔离。

2.如何使用ThreadLocal进行优化

话不多说,基于我们开头的例子,我迫不及待地用ThreadLocal来优化一下。

2.1 构建基于ThreadLocal的上下文

定义一个SessionUser类,存储用户信息,包括用户id、用户名。

然后定义一个基于ThreadLocal的上下文SessionUserContext,代码如下所示。

用ThreadLocal来优化下代码吧

 

2.2 信息存入ThreadLocal中

在我们的优化案例中,就是存入用户信息。

解析请求中的用户信息有很多方法。本文以HandlerIntercept为例,说明下MVC中的一种方式。

  • 实现HandlerIntercept接口
  • 重写preHandler方法
  • 解析HttpServletRequest,获取用户信息
  • 用户信息存于SessionUserContext

源码如下所示。

用ThreadLocal来优化下代码吧

 

2.3 在需要的地方获取信息

原本需要传入CurrentUser的参数都可以去掉了。

在需要用户信息的时候,直接从SessionUserContext中获取即可。

用ThreadLocal来优化下代码吧

 

哈哈,是不是看起来一下子清爽了很多。

可以在任何地方获取user信息,不再需要层层传递用户信息了。

用ThreadLocal来优化下代码吧

 

3.ThreadLocal实现原理

上面我们已经知道了怎么通过ThreadLocal进行优化。

下面,我们要 知其然知其所以然,一起看看ThreadLocal实现原理吧。

3.1 set方法

Set方法应该是ThreadLocal的核心逻辑了。

主要三步:

  • 获取当前线程
  • 获取ThreadLocalMap对象
  • 如果ThreadLocalMap对象存在,则将当前线程对象作为key,要存储的对象作为value存到map中 如果ThreadLocalMap对象不存在,就调用creatMap( )进行创建
用ThreadLocal来优化下代码吧

 

3.2 ThreadLocalMap是什么。

ThreadLocalMap是一个定义在ThreadLocal类内部的静态类,里面还定义了一个Entry类作为存储值的地方。

ThreadLocalMap的key是当前ThreadLocal对象,value是我们要存储的值(对象)。

用ThreadLocal来优化下代码吧

 

调用creatMap的时候,就是新建一个ThreadLocalMap对象

用ThreadLocal来优化下代码吧

 

同时,ThreadLocalMap在Thread类中作为一个属性存在。

用ThreadLocal来优化下代码吧

 

每个线程Thread维护了ThreadLocalMap这么一个Map,这个map的key是LocalThread对象本身,value则是要存储的对象

3.3 get方法

Get方法就比较简单了,就是从map中取值的过程。

用ThreadLocal来优化下代码吧

 

3.4 ThreadLocal小结

现在,让我们重新梳理一遍,看看ThreadLocal是如何实现变量的线程隔离的:

  • 每个Thread维护着一个ThreadLocalMap的引用
  • ThreadLocalMap是ThreadLocal的内部类,用Entry来进行存储,key是ThreadLocal对象,值是传递进来的对象
  • 调用ThreadLocal的get()/set()方法时,实际上就是以ThreadLocal对象为key,在ThreadLocalMap中读写value

 

4.实战要点

在一开始的优化设计中,不知道大家有没有注意到对ThreadLocal的remove调用。

用ThreadLocal来优化下代码吧

 

这里就需要谈谈ThreadLocal使用时的,两个要点。尤其是在使用线程池的时候使用ThreadLocal。

4.1 避免内存泄露

用ThreadLocal来优化下代码吧

 

在ThreadLocalMap介绍的时候,我们可以看到,ThreadLocalMap是Thread的一个属性。因此,ThreadLocalMap和Thread的生命周期是一样的。

如果没有手动删除对应的ThreadLocal的key,那么就会造成内存泄漏无法回收。尤其在线程池环境下,线程会被不断复用。

4.2 线程池避免重复线程变量影响

以前文优化案例为例。

在MVC中,每次请求进来会使用线程池复用线程。如果请求带了用户信息,那么就会重置ThreadLocal对应的用户信息,如果请求没有带用户信息,必须手动清除一下当前ThreadLocal对应的变量,否则后面使用过程中可能会造成混乱。

 

都看到最后了,原创不易,点个关注,点个赞吧~

文章持续更新,可以微信搜索「阿丸笔记 」第一时间阅读,回复关键字【学习】有我准备的一线大厂面试资料。

知识碎片重新梳理,构建Java知识图谱:
github.com/saigu/JavaK…(历史文章查阅非常方便)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/2608.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Windows下面的Netstat命令详解

    Windows下面的Netstat命令详解  netstat[-a][-e][-n][-o][-pProtocol][-r][-s][Interval] 参数解释:-a 显示所有活动的TCP连接以及计算机侦听的TCP和UDP端口。 -e 显示以太网统计信息,如发送和接收的字节数、数据包数。该参数可以与-s结合使用。 -n 显示活动的TCP连接,不过,只以数字…

    2022年5月30日
    39
  • SpringBoot集成kafka全面实战「建议收藏」

    SpringBoot集成kafka全面实战「建议收藏」本文是SpringBoot+Kafka的实战讲解,如果对kafka的架构原理还不了解的读者,建议先看一下《大白话kafka架构原理》、《秒懂kafkaHA(高可用)》两篇文章。一、生产者实践 普通生产者 带回调的生产者 自定义分区器 kafka事务提交 二、消费者实践 简单消费 指定topic、partition、offset消费 …

    2022年6月12日
    31
  • 测试显卡矿卡用什么软件,3分钟看懂:AMD二手矿卡简明鉴别、检测教程,从此脱坑不求人…「建议收藏」

    测试显卡矿卡用什么软件,3分钟看懂:AMD二手矿卡简明鉴别、检测教程,从此脱坑不求人…「建议收藏」3分钟看懂:AMD二手矿卡简明鉴别、检测教程,从此脱坑不求人2020-03-2700:10:00135点赞716收藏90评论创作立场声明:Tony哥的矿卡日记二手矿卡坑太深,手握秘籍不求人AMD自2016年中发布Polaris系列GPU至今,长达四年的时间里,一代又一代的RX470、480、570、580等显示卡进入暗无天日的区块链矿场,挥洒着血泪和青春。在经历一次次矿难之后,貌似廉价的二手矿卡…

    2022年6月5日
    692
  • 数据库的隔离级别

    数据库的隔离级别本文主要介绍了数据库中的隔离级别,以及其会产生的场景。

    2022年5月10日
    41
  • 测试音视频地址(音视频性能测试)

    在线视频地址https://media.w3.org/2010/05/sintel/trailer.mp4http://clips.vorwaerts-gmbh.de/big_buck_bunny.mp4http://vjs.zencdn.net/v/oceans.mp4https://media.w3.org/2010/05/sintel/trailer.mp4http://…

    2022年4月13日
    68
  • 图遍历算法的应用

    图遍历算法的应用1.判断图的连通性图的遍历算法可以用来判断图的连通性。如果一个无向图是联通的,如果无向图是联通的,则从任一节点出发,仅需一次遍历就可以访问图中的所有节点。如果无向图是非联通的,则从某一节点出发,一次遍历仅能访问到该顶点所在联通分量的所有顶点,而对于图中其他联通分量的顶点,则无法通过这次遍历访问。对于有向图来说,若从初始点到图中的每个顶点都有路径,则能够访问到图中的所有顶点,否则不能访问到所有顶…

    2022年5月4日
    47

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号