乐趣区

关于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…(历史文章查阅十分不便)

退出移动版