1.用法 <开发艺术>P376代码
private ThreadLocal<Boolean> mBooleanThreadLocal = new ThreadLocal<Boolean>();
...
mBooleanThreadLocal.set(true);
mBooleanThreadLocal.get();
...
new Thread() {
public void run() {
mBooleanThreadLocal.set(false);
sys(mBooleanThreadLocal.get());
}
}
综上:
入口1:new ThreadLocal<Boolean>()
入口2:mBooleanThreadLocal.set(false);
入口3:mBooleanThreadLocal.get();
2.根据入口分析源代码:
2.1 入口1:new ThreadLocal<Boolean>()
ThreadLocal.java
public ThreadLocal() {}
2.2 入口2:mBooleanThreadLocal.set(false);
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread); // 第一次调用values都是空
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value); // this:ThreadLocal对象
}
Values values(Thread current) {
// Thread.java中定义 ThreadLocal.Values localValues; //Normal thread local values.
return current.localValues;
}
Values initializeValues(Thread current) {
return current.localValues = new Values();
}
// Values类(内部类)
// Values类内部使用数组(类似哈希表)保存键值对(key:ThreadLocal value:T泛型)
/**
* Per-thread map of ThreadLocal instances to values. 线程map
*/
static class Values {
/**
* Map entries. Contains alternating keys (ThreadLocal) and values.
*/
private Object[] table;
/**
* Sets entry for given ThreadLocal to given value, creating an
* entry if necessary.
*/
void put(ThreadLocal<?> key, Object value) {
// Keep track of first tombstone. That's where we want to go back
// and add an entry if necessary.
int firstTombstone = -1;
for (int index = key.hash & mask;; index = next(index)) {
Object k = table[index];
if (k == key.reference) { // 修改已有key的值
// Replace existing entry.
table[index + 1] = value;
return;
}
if (k == null) {
if (firstTombstone == -1) {
// Fill in null slot.
table[index] = key.reference; // 第一个索引存key,接下去一个索引存value
table[index + 1] = value;
size++;
return;
}
// Go back and replace first tombstone.
table[firstTombstone] = key.reference;
table[firstTombstone + 1] = value;
tombstones--;
size++;
return;
}
...
}
}
private int next(int index) {
return (index + 2) & mask;
}
}
2.3 入口3:mBooleanThreadLocal.get();
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table; // 本质调用:Values类中成员/方法
int index = hash & values.mask;
if (this.reference == table[index]) { // 之前有put数据
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread); // 未put数据
}
return (T) values.getAfterMiss(this); // 还未put的时候:返回null
}
3.总结:
3.1 整个过程涉及到三个类:ThreadLocal类,Thread类(内部有成员Values),Values类(ThreadLocal类的内部类)
每个Thread类内部都有一个Values成员,而Values成员包含键值对(ThreadLocal, T泛型数据)
对ThreadLocal类的put和get操作本质是操作对应线程的Values成员变量键值对(ThreadLocal, T泛型数据)
多个线程可以保存同一个ThreadLocal对象的引用,但是对应的值是副本形式,而不是共同的引用
3.2
入口2:mBooleanThreadLocal.set(false); // ThreadLocal类
ThreadLocal的set方法只做一些错误和简单逻辑判断,真正维护键值对(ThreadLocal,T泛型)和set操作是在Values类(核心)
入口3:mBooleanThreadLocal.get(); // ThreadLocal类
ThreadLocal的get方法只做一些错误和简单逻辑判断,真正维护键值对(ThreadLocal,T泛型)和get操作是在Values类(核心)
Values类从已经保存的Object[]数组中找到之前set操作存入的键值对,并返回key对应的value
4.思考:如果自己会如何实现?
自己实现:ThreadLocal类内部维护一个Map,key:thread value:T(真正的数据).这样put的时候根据线程和value存成一个键值对
源码实现:每个Thread中自己维护一个Values变量(ThreadLocal类的内部类),put的时候,把ThreadLocal引用和真正数据保存到Thread对应的
成员变量Values(可以看做维护一个Map,key:ThreadLocal value:真正数据),这样Values成员就能保存对个Item(key:ThreadLocal value:真正数据)
ThreadLocal实现
最新推荐文章于 2023-07-11 16:03:40 发布