关于java:用ThreadLocal来优化下代码吧

微信搜寻【阿丸笔记】,关注Java/MySQL/中间件各系列原创实战笔记,干货满满。

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

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

它的用意是心愿在办法内应用user的信息,然而如此大范畴的传递用户信息,第一感觉就是不优雅。那有什么方法能够优化一下呢?

咱们第一反馈是,能够存一个全局变量,在初始地位将用户信息存入全局变量,而后在须要的中央去get一下。

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

能够用线程的id去作为map的key,将该申请的用户信息作为map的value。

咦?很相熟的感觉。

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

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

1.什么是ThreadLocal

================

先来看下JDK的正文:

简略翻译过去,就是说:

ThreadLocal提供了线程隔离的局部变量,通过get( )和set( )办法操作以后线程对应的变量,而且不会和其余线程抵触,实现了基于线程的数据隔离。

2.如何应用ThreadLocal进行优化

=====================

话不多说,基于咱们结尾的例子,我急不可待地用ThreadLocal来优化一下。

2.1 构建基于ThreadLocal的上下文

=======================

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

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

2.2 信息存入ThreadLocal中

=====================

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

解析申请中的用户信息有很多办法。本文以HandlerIntercept为例,阐明下MVC中的一种形式。

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

源码如下所示。

2.3 在须要的中央获取信息

==============

本来须要传入CurrentUser的参数都能够去掉了。

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

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

能够在任何中央获取user信息,不再须要层层传递用户信息了。

3.ThreadLocal实现原理

=================

下面咱们曾经晓得了怎么通过ThreadLocal进行优化。

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

3.1 set办法

=========

Set办法应该是ThreadLocal的外围逻辑了。

次要三步:

  • 获取以后线程
  • 获取ThreadLocalMap对象
  • 如果ThreadLocalMap对象存在,则将以后线程对象作为key,要存储的对象作为value存到map中 如果ThreadLocalMap对象不存在,就调用creatMap( )进行创立

3.2 ThreadLocalMap是什么

======================

ThreadLocalMap是一个定义在ThreadLocal类外部的动态类,外面还定义了一个Entry类作为存储值的中央。

ThreadLocalMap的key是以后ThreadLocal对象,value是咱们要存储的值(对象)。

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

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

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

3.3 get办法

=========

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

3.4 ThreadLocal小结

=================

当初,让咱们从新梳理一遍,看看ThreadLocal是如何实现变量的线程隔离的:

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

4.实战要点

======

在一开始的优化设计中,不晓得大家有没有留神到对ThreadLocal的remove调用。

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

4.1 防止内存泄露

==========

在ThreadLocalMap介绍的时候,咱们能够看到,ThreadLocalMap是Thread的一个属性。因而,ThreadLocalMap和Thread的生命周期是一样的。

如果没有手动删除对应的ThreadLocal的key,那么就会造成内存透露无奈回收。尤其在线程池环境下,线程会被一直复用。

4.2 线程池防止反复线程变量影响

=================

以前文优化案例为例。

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

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

文章继续更新,能够微信搜寻「阿丸笔记 」第一工夫浏览,回复【笔记】获取Canal、MySQL、HBase、JAVA实战笔记,回复【材料】获取一线大厂面试材料。

常识碎片从新梳理,构建Java常识图谱:github.com/saigu/JavaK…(历史文章查阅十分不便)

评论

发表回复

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

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理