ThreadLocal

ThreadLocal:

ThreadLocal: 线程本地存储区(Thread Local Storage,简称为TLS),每个线程都有自己的私有的本地存储区域,不同线程之间彼此不能访问对方的TLS区域。

ThreadLocal类不过是为了执行set/get,确定泛型的工具人而已。真正数据是靠的每个Thread内部维护。

实际上就是 每个Thread对象中 维护了一个

叫ThreadLocal.ThreadLocalMap的

**key为 ThreadLocal对象, value为 存储的值 **

的key-vale映射结构,(实际上是一个键值对组成entry的唯一环形数组,线性探测,初始值3/4容量扩容)

当调用threadLocalInstance.set(value)时,其实时调用的CurrentThread.threadLocalMap.set(threadLocalInstance, value)

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
68
69
70
71
72
73
74
75

public class Main {

public static void main(String[] args) {
ThreadLocal<String> threadLocalOne = new ThreadLocal<>();
ThreadLocal<String> threadLocalTwo = new ThreadLocal<>();

new Thread(new Runnable() {
@Override
public void run() {
threadLocalOne.set("线程一的数据 --- threadLocalOne");
threadLocalTwo.set("线程一的数据 --- threadLocalTwo");
System.out.println(threadLocalOne.get());
System.out.println(threadLocalTwo.get());
}
}).start();

new Thread(new Runnable() {
@Override
public void run() {
System.out.println(threadLocalOne.get());
System.out.println(threadLocalTwo.get());
threadLocalOne.set("线程二的数据 --- threadLocalOne");
threadLocalTwo.set("线程二的数据 --- threadLocalTwo");
System.out.println(threadLocalOne.get());
System.out.println(threadLocalTwo.get());
}
}).start();
}
}

//线程一的数据 --- threadLocalOne
//线程一的数据 --- threadLocalTwo
//null
//null
//线程二的数据 --- threadLocalOne
//线程二的数据 --- threadLocalTwo


#ThreadLocal.class {
//存数据,若当前线程未曾调用过ThreadLocal.set,则为thread初始化一个ThreadLocalMap
public void set(T value) {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null)
map.set(this, value);
else
createMap(t, value);
}

//获取当前Thread的threadLocalMap变量,以ThreadLocal为key,从threadLocalMap中取值
public T get() {
Thread t = Thread.currentThread();
ThreadLocalMap map = getMap(t);
if (map != null) {
ThreadLocalMap.Entry e = map.getEntry(this);
if (e != null) {
@SuppressWarnings("unchecked")
T result = (T)e.value;
return result;
}
}
//当线程对应ThreadLocalMap未存储该key时,返回null
return setInitialValue();
}

ThreadLocalMap getMap(Thread t) {
return t.threadLocals;
}

void createMap(Thread t, T firstValue) {
t.threadLocals = new ThreadLocalMap(this, firstValue);
}

}
1
2
Entry[] tab = table;
tab[i] = new Entry(key, value);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class ThreadLocal<T> {

...

static class ThreadLocalMap {
...

private static int nextIndex(int i, int len) {
return ((i + 1 < len) ? i + 1 : 0);
}

...
}
}

应用场景1:每个线程对应一个Looper

Looper.prepare():在每个线程只允许执行一次,该方法会创建Looper对象,Looper的构造方法中会创建一个MessageQueue对象,再将Looper对象保存到当前线程TLS

1
2
3
4
5
6
7
8
private static void prepare(boolean quitAllowed) {
//每个线程只允许执行一次该方法,第二次执行时线程的TLS已有数据,则会抛出异常。
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
//创建Looper对象,并保存到当前线程的TLS区域
sThreadLocal.set(new Looper(quitAllowed));
}

应用场景2:Choreographer是主线程的ThradLocal变量

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
public final class Choreographer {

// Thread local storage for the choreographer.
private static final ThreadLocal<Choreographer> sThreadInstance =
new ThreadLocal<Choreographer>() {
@Override
protected Choreographer initialValue() {
Looper looper = Looper.myLooper();
if (looper == null) {
throw new IllegalStateException("The current thread must have a looper!");
}
// 创建 Choreographer 对象
Choreographer choreographer = new Choreographer(looper, VSYNC_SOURCE_APP);
if (looper == Looper.getMainLooper()) {
mMainInstance = choreographer;
}
return choreographer;
}
};

private static volatile Choreographer mMainInstance;

public static Choreographer getInstance() {
return sThreadInstance.get();
}

}

从 Choreographer 的 getInstance 方法中, 我们可以看到它调用 ThreadLocal.get 方法, 从当前线程的 ThreadLocalMap 散列表中获取以这个 ThreadLocal 为 Key 的 Value 值, 若 Value 不存在, 则会调用 initialValue 创建 Choreographer 实例对象

由此我们可以得出 Choreographer 是线程单例的, 并且它只能运行在存在 Looper 的线程中,

Author

white crow

Posted on

2021-05-14

Updated on

2024-03-25

Licensed under