ThreadLocal 源码阅读笔记

338 阅读2分钟

大略的看了个大概,ThreadLocal.ThreadLocalMap内部的实现细节后边补充

理解:

线程的本地变量,赋值之后,多个线程之间的值不可见。 结合线程池使用时线程结束时要清除本次使用的本地变量。

整体:每个线程内部维护了一个ThreadLocal.ThreadLocalMap的变量threadLocals(key:ThreadLocal,value),ThreadLocal赋值取值时操作的其实都是该变量,该变量是每个线程的私有变量,必然不同线程之间不可见。

ThreadLocal threadLocal = new ThreadLocal<>();
1、threadLocal.set()

set方法中,首先获取当前线程ThreadCurrent.currentThread(),然后getMap(Threadt)获取获取线程的ThreadLocal.ThreadLocalMap 变量,不为空,set值key为当前的TheadLocal实例,value为传入的value值,为空创建一个空的ThreadCurrent.currentThread()并赋值。

2、threadLocal.get()

先获取当前线程ThreadCurrent.currentThread();获取当前线程的ThreadLocal.ThreadLocalMap 变量,若为空,返回空值,若不为空,根据当前的TheadLocal实例获取对应的value值

3、threadLocal.remove() 从当前线程中移除以当前ThreadLocal的实例为key的值


应用实例:mysql动态数据源切换

需求:根据已有的主从数据库环境,将部分查询请求分散到从库上。
此处只给出大概思路,并不贴出详细

思路:自定义注解+切面+ ThreadLocal+AbstractRoutingDataSource(动态数据源)

在mybatis接口方法上添加自定义注解,通过切面在执行前获取切面上的参数(动态数据源的key),ThreadLocal将获取的key写入本地线程变量,DynamicRoutingDataSource在获取连接时从ThreadLocal读取当前查询指定的数据源。

自定义注解:

切面:

其热点配置mapper接口的方法,前置切面获取自定义注解中的数据库标志以及是否为只读,根据从注解中获取到的数据库名称和只读标志赋值,DynamicDataSourceContextHolder.set* 其实就是ThreadLocal.set后边给出截图实例

记得切面后清除线程的本地变量

重写AbstractRoutingDataSource的determineCurrentLookupKey方法,从ThreadLocal中获取指定的数据源的key

另外动态数据源的配置: