微信搜寻【阿丸笔记】,关注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…(历史文章查阅十分不便)
发表回复