ThreadLocal表层分析

直接开始

之前在写自定义注解实现多数据源的那篇文章中用过这个ThreadLocal,用这个主要是让每个线程内部有自己独立的数据源信息,就意味着每个线程内部存储着一个单独的数据库连接,这是开始,来看一下是怎么实现的。

概述

这个在我看来,看懂了之后很好理解,其实就是在Thread里面维护了一个ThreadLocalMap,然后就做到了线程里面的数据隔离,这个Map用当前线程来做key值,需要存储的对象作为value。大致的意思就是这样了,回过头来说说之前写的自定义注解实现多数据源达到读写分离的目的就是这样,每个方法调用的线程,在执行时,会去判断是使用的哪个数据源,然后切换,保存到ThreadLocalMap里面,保证了当前方法里面都是从指定的数据源操作数据

源码

不多说了,也没什么说的,直接看源码吧,挺简单的,主要是两个方法 get()set()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/**
* Returns the value in the current thread's copy of this
* thread-local variable. If the variable has no value for the
* current thread, it is first initialized to the value returned
* by an invocation of the {@link #initialValue} method.
*
* @return the current thread's value of this thread-local
*/
public T get() {
//获取到当前线程
Thread t = Thread.currentThread();
//获取当前线程的ThreadLocalMap
ThreadLocalMap map = getMap(t);
if (map != null) {
//取到以当前线程为key的值
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
//转换格式直接返回
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//如果没有map或者值为null,则初始化一个值为null,返回
return setInitialValue();
}
/**
* Variant of set() to establish initialValue. Used instead
* of set() in case user has overridden the set() method.
* 设置初始值 为null
* @return the initial value
*/

private T setInitialValue() {
T value = initialValue();
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
return value;
}
protected T initialValue() {
return null;
}
/**
* Sets the current thread's copy of this thread-local variable
* to the specified value. Most subclasses will have no need to
* override this method, relying solely on the {@link #initialValue}
* method to set the values of thread-locals.
*
* @param value the value to be stored in the current thread's copy of
* this thread-local.
*/
public void set(T value) {
//获取当前线程
Thread t = Thread.currentThread();
//依旧是getmMap
ThreadLocalMap map = getMap(t);
if (map != null)
//设置值
map.set(this, value);
else
//没有这个Map就创建这个map
createMap(t, value);
}

get和set到这就没了,这两个方法挺简单的,但是ThreadLocalMap里面是维护的一个Entry数组,这个数组使用的是弱引用,弱引用在深入理解Java虚拟机的时候讲了一下,这里用上了,就在看看

弱引用:

WeakReference 在每次执行GC的时候就会将这块清除掉,不用管内存是否足够,但是这里有个问题,就是只在key上面用了弱引用,但是此时value值还没有被垃圾回收,所以要完全回收这块的数据,只靠弱引用是没办法完全清除的,必须要调用一下ThreadLocal的remove方法,他会将value的值设置为null,等待GC

-------------本文结束感谢您的阅读-------------
0%