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