2.ThreadLocal实现原理
本文分析源代码基于Android6.0。
代码路径:
libcore/luni/src/main/java/java/lang/ThreadLocal.java
libcore/libart/src/main/java/java/lang/Thread.java
从API官方文档看,ThreadLocal提供了这样一些接口:
public:set()/get()/remove()
protected:initialValue()
从这几个API入手看一下ThreadLocal源代码。
ThreadLocal.java:
/**
* Sets the value of this variable for the current thread. If set to
* {@code null}, the value will be set to null and the underlying entry will
* still be present.
*
* @param value the new value of the variable for the caller thread.
*/
public void set(T value) {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values == null) {
values = initializeValues(currentThread);
}
values.put(this, value);
}
/**
* Returns the value of this variable for the current thread. If an entry
* doesn't yet exist for this variable on this thread, this method will
* create an entry, populating the value with the result of
* {@link #initialValue()}.
*
* @return the current value of the variable for the calling thread.
*/
@SuppressWarnings("unchecked")
public T get() {
// Optimized for the fast path.
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
Object[] table = values.table;
int index = hash & values.mask;
if (this.reference == table[index]) {
return (T) table[index + 1];
}
} else {
values = initializeValues(currentThread);
}
return (T) values.getAfterMiss(this);
}
/**
* Removes the entry for this variable in the current thread. If this call
* is followed by a {@link #get()} before a {@link #set},
* {@code #get()} will call {@link #initialValue()} and create a new
* entry with the resulting value.
*
* @since 1.5
*/
public void remove() {
Thread currentThread = Thread.currentThread();
Values values = values(currentThread);
if (values != null) {
values.remove(this);
}
}
梳理一下整个逻辑:
set()/get()/remove(),从当前线程拿到其Values成员变量。Values是定义在ThreadLocal内部的一个包级可见的内部类,是一个类似Map的数据结构,实现从ThreadLocal(作为Key)到Object(作为Value)的映射。在Thread中,只定义了这样一个包级可见的成员变量,没有任何的维护逻辑,维护逻辑都在ThreadLocal中。
上面是大概框架,下面从一些点来仔细研究其实现机制。
2.1ThreadLocal对于Thread.localValues的维护
ThreadLocal得到当前线程的Values方法如下:
/**
* Gets Values instance for this thread and variable type.
*/
Values values(Thread current) {
return current.localValues;
}
Thread.java:
/**
* Normal thread local values.
*/
ThreadLocal.Values localValues;
在Thread中,只定义了这样一个包级可见的成员变量,没有任何的维护逻辑,维护逻辑都在ThreadLocal中。
(1)初始化
values()方法获取到localValues的引用,如果发现尚为null,通过initializeValues()初始化
/**
* Creates Values instance for this thread and variable type.
*/
Values initializeValues(Thread current) {
return current.localValues = new Values();
}
接下来看看Values类的构造方法
/**
* Constructs a new, empty instance.
*/
Values() {
initializeTable(INITIAL_SIZE);
this.size = 0;
this.tombstones = 0;
}
/**
* Used for InheritableThreadLocals.
*/
Values(Values fromParent) {
this.table = fromParent.table.clone();
this.mask = fromParent.mask;
this.size = fromParent.size;
this.tombstones = fromParent.tombstones;
this.maximumLoad = fromParent.maximumLoad;
this.clean = fromParent.clean;
inheritValues(fromParent);
}
前者比较简单。后者是从一个Parent Values对象创建一个新的Values对象,应用于InheritableThreadLocal。继承稍后介绍。
(2)继承
InheritableThreadLocal是ThreadLocal的一个子类,这里不扩展介绍。继续看看Values的inheritValues()方法
/**
* Inherits values from a parent thread.
*/
@SuppressWarnings({"unchecked"})
private void inheritValues(Values fromParent) {
// Transfer values from parent to child thread.
Object[] table = this.table;
for (int i = table.length - 2; i >= 0; i -= 2) {
Object k = table[i];
if (k == null || k == TOMBSTONE) {
// Skip this entry.
continue;
}
// The table can only contain null, tombstones and references.
Reference<InheritableThreadLocal<?>> reference
= (Reference<InheritableThreadLocal<?>>) k;
// Raw type enables us to pass in an Object below.
InheritableThreadLocal key = reference.get();
if (key != null) {
// Replace value with filtered value.
// We should just let exceptions bubble out and tank
// the thread creation
table[i + 1] = key.childValue(fromParent.table[i + 1]);
} else {
// The key was reclaimed.
table[i] = TOMBSTONE;
table[i + 1] = null;
fromParent.table[i] = TOMBSTONE;
fromParent.table[i + 1] = null;
tombstones++;
fromParent.tombstones++;
size--;
fromParent.size--;
}
}
}
这个方法的作用即从父Thread继承线程本地变量值。