解析ThreadLocal源码
之前做项目是为了提升服务性能,将我们的数据库做了读写分离,其中核心的数据库动态切换就是使用ThreadLocal实现的,下面我们就通过ThreadLocal源码解析它是怎么帮我们做到数据库动态切换的。
在看ThreadLocal的源码之前我们先来了解一下ThreadLocal的主要特点是什么,就以我实际项目中为例,为了提升数据库的读写性能,一台数据库已经无法解决越来越多的读写请求操作了,那么这个时候将数据库的读写操作分离开,相当于将数据库的性能提升了一倍,那么怎么将读写操作分离开呢,并且让这两个数据库的操作在多线程的情况下互不干扰,我们知道数据库从连接到执行完sql提交事物然后关闭连接这是一个周期,如果在这个周期里有两个线程分别使用读库和写库进行操作,那么肯定会产生冲突的,如果我们能让每个线程里都有一个数据库connection的副本对象,每个线程都是用自己内部的副本对象,那这个问题不就解决了吗,ThreadLocal就是java为我们提供每个线程内部保存副本对象的工具。
从上图中我们可以看到ThreadLocal中方法并不是很多,我们就查看它几个主要的方法实现,来看一下它是怎么做到每个线程都新建一个副本的。
ThreadLocal方法源码分析
get方法:
从上面的源码中我们可以看到,这个方法主要做了四件事:1、获取当前线程;2、从当前线程中获取ThreadLocalMap;3、如果map不为null,那么就将map中的value返回;4、map为null那么就调用setInitialValue方法重新new一个新值返回;第一步们什么好说的,我们从第二步getMap()看一下这个ThreadLocalMap是个什么东西,主要的功能是什么。
getMap方法:
从源码中我们可以获得两个信息,1、ThreadLocalMap是thread中的一个属性;2、ThreadLocalMap的实现是一个Entry其中k为ThreadLocal;value是一个Object对象;从这里我们可以看到ThreadLocal和Thread的关系了,我们继续向下分析。
setInitialValue方法:
如果当前线程中的ThreadLocalMap为null,那么就会调用setInitialValue方法初始化一个值并且返回,这个方法里前边还是检查了一下ThreadLocalMap,如果不为null那么就将当前的ThreadLocal和initialValue方法初始化的值放到map中并且返回value,如果为null那么就调用createMap方法将当前线程t和value 传入并返回value的值;从这里我们终于找到了每个线程里的变量副本都是从哪里初始化出来的了,那就是initialValue方法。
initialValue方法:
initialValue方法非常简单,它默认返回的是个null,但是它使用protected修饰,那么我们可以在创建ThreadLocal对象的时候可以重写这个方法,返回我们想要的对象副本,这样我们就可以通过每次调用initialValue方法初始化一个副本对象了。
createMap方法:
createMap方法有两个参数分别是线程t和副本对象firstValue,它里边的逻辑也非常简单,初始化线程t中的ThreadLocalMap对象,并且将ThreadLocal对象和副本对象firstValus作为参数保存到map里。
remove方法:
ThreadLocal中的remove方法,是从当前线程中取出ThreadLocalMap,将自己作为key传入remove方法中,将自己在ThreadLocalMap中的对象副本移除。
总结
从上边的源码分析中我们了解到TheadLocal是通过ThreadLocalMap属性将自己和副本对象保存在当前线程的,而ThreadLocalMap在线程初始化的时候是空的,当调用ThreadLocal中的createMap方法时,才会创建map对象并且将当前线程和副本对象进行绑定保存。