线程成员 threadLocals
线程类Thread内部有一个变量:threadLocals
它是 ThreadLocal.ThreadLocalMap 对象
1 | ... |
2 | public |
3 | class Thread implements Runnable { |
4 | ... |
5 | // line 179 |
6 | /* ThreadLocal values pertaining to this thread. This map is maintained |
7 | * by the ThreadLocal class. */ |
8 | ThreadLocal.ThreadLocalMap threadLocals = null; |
9 | ... |
10 | } |
类ThreadLocalMap
ThreadLocalMap 是 ThreadLocal 的内部类
1 | public class ThreadLocal<T> { |
2 | ... |
3 | // line 287 |
4 | /** |
5 | * ThreadLocalMap is a customized hash map suitable only for |
6 | * maintaining thread local values. No operations are exported |
7 | * outside of the ThreadLocal class. The class is package private to |
8 | * allow declaration of fields in class Thread. To help deal with |
9 | * very large and long-lived usages, the hash table entries use |
10 | * WeakReferences for keys. However, since reference queues are not |
11 | * used, stale entries are guaranteed to be removed only when |
12 | * the table starts running out of space. |
13 | */ |
14 | static class ThreadLocalMap { |
15 | // ... |
16 | } |
17 | ... |
18 | } |
ThreadLocalMap is a customized hash map suitable only for maintaining thread local values.
大意:ThreadLocalMap 是一个自定义 HashMap,只适用于线程局部变量。
完全可以把它看做是一个 HashMap。也就是说,Thread 有一个类似 HashMap 的成员变量
类ThreadLocal
1 | /** |
2 | * This class provides thread-local variables. These variables differ from |
3 | * their normal counterparts in that each thread that accesses one (via its |
4 | * {@code get} or {@code set} method) has its own, independently initialized |
5 | * copy of the variable. {@code ThreadLocal} instances are typically private |
6 | * static fields in classes that wish to associate state with a thread (e.g., |
7 | * a user ID or Transaction ID). |
8 | * |
9 | * <p>For example, the class below generates unique identifiers local to each |
10 | * thread. |
11 | * A thread's id is assigned the first time it invokes {@code ThreadId.get()} |
12 | * and remains unchanged on subsequent calls. |
13 | * |
14 | * ... |
15 | * |
16 | * @author Josh Bloch and Doug Lea |
17 | * @since 1.2 |
18 | */ |
19 | public class ThreadLocal<T> { |
20 | //... |
21 | } |
注释大意:ThreadLocal 提供线程局部的变量,这些变量在每个线程中都有不同的副本,通过get和set方法就可以获取和设置它们。
类ThreadLocal的结构如下:
重要的方法只有两个:set 和 get
ThreadLocal.set(value)
ThreadLocal.set(value) 向 Thread 内部的 threadLocals 变量添加一个元素,它的实现如下:
1 | // line 189 |
2 | /** |
3 | * Sets the current thread's copy of this thread-local variable |
4 | * to the specified value. Most subclasses will have no need to |
5 | * override this method, relying solely on the {@link #initialValue} |
6 | * method to set the values of thread-locals. |
7 | * |
8 | * @param value the value to be stored in the current thread's copy of |
9 | * this thread-local. |
10 | */ |
11 | public void set(T value) { |
12 | // 获取当前线程 |
13 | Thread t = Thread.currentThread(); |
14 | // 获取线程内部 ThreadLocalMap 对象 |
15 | ThreadLocalMap map = getMap(t); |
16 | if (map != null) |
17 | map.set(this, value); |
18 | else// 给线程threadLocals变量new一个ThreadLocalMap对象,并添加第一个键值对 |
19 | createMap(t, value); |
20 | } |
21 | ...... |
22 | // line 225 |
23 | /** |
24 | * Get the map associated with a ThreadLocal. Overridden in |
25 | * InheritableThreadLocal. |
26 | * |
27 | * @param t the current thread |
28 | * @return the map |
29 | */ |
30 | ThreadLocalMap getMap(Thread t) { |
31 | return t.threadLocals; |
32 | } |
33 | |
34 | /** |
35 | * Create the map associated with a ThreadLocal. Overridden in |
36 | * InheritableThreadLocal. |
37 | * |
38 | * @param t the current thread |
39 | * @param firstValue value for the initial entry of the map |
40 | */ |
41 | void createMap(Thread t, T firstValue) { |
42 | t.threadLocals = new ThreadLocalMap(this, firstValue); |
43 | } |
ThreadLocal.get()
1 | public T get() { |
2 | Thread t = Thread.currentThread(); |
3 | ThreadLocalMap map = getMap(t); |
4 | if (map != null) { |
5 | ThreadLocalMap.Entry e = map.getEntry(this); |
6 | if (e != null) { |
7 | ("unchecked") |
8 | T result = (T)e.value; |
9 | return result; |
10 | } |
11 | } |
12 | return setInitialValue(); |
13 | } |
小结
ThreadLocal 和 Synchronized 都是为了解决多线程中相同变量的访问冲突问题,不同的是:
- Synchronized 是通过线程等待,牺牲时间来解决访问冲突
- ThreadLocal 是通过每个线程单独一份存储空间,牺牲空间来解决冲突,并且相比于
Synchronized,ThreadLocal 具有线程隔离的效果,只有在线程内才能获取到对应的值,线程外则不能访问到想要的值。
正因为 ThreadLocal 的线程隔离特性,使他的应用场景相对来说更为特殊一些。
当某些数据是 以线程为作用域并且不同线程具有不同的数据副本 的时候,就可以考虑采用ThreadLocal。
比如:在多数据源切换时,就使用了 ThreadLocal 来设置当前使用的数据源