FastThreadLocal的get方法实现我们通过以下三部分分析:
1、获取ThreadLocalMap
2、直接通过索引找到对象
3、如果对象为空,那就初始化对象
我们从FastThreadLocal的get方法进入:
/**
* Returns the current value for the current thread
*/
public final V get() {
return get(InternalThreadLocalMap.get());
}
一、获取ThreadLocalMap
InternalThreadLocalMap.get()就是我么这个过程,查看源码:
public static InternalThreadLocalMap get() {
Thread thread = Thread.currentThread();
if (thread instanceof FastThreadLocalThread) {
return fastGet((FastThreadLocalThread) thread);
} else {
return slowGet();
}
}
这里又fastGet和slowGet,slowGet就是线程不为FastThreadLocalThread的时候,我们先看slowGet方法的实现:
private static InternalThreadLocalMap slowGet() {
ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = UnpaddedInternalThreadLocalMap.slowThreadLocalMap;
InternalThreadLocalMap ret = slowThreadLocalMap.get();
if (ret == null) {
ret = new InternalThreadLocalMap();
slowThreadLocalMap.set(ret);
}
return ret;
}
通过slowThreadLocalMap的get方法找出InternalThreadLocalMap,然后如果不存在就创建一个并放到slowThreadLocalMap里面,那么这个slowThreadLocalMap是什么的?
static final ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = new ThreadLocal<InternalThreadLocalMap>();
这个 slowThreadLocalMap是jdk原生的ThreadLocal里面的对象。
意思就是InternalThreadLocalMap是通过ThreadLocal的get方法里面把它取出来的,相对来说更加"slow",那么fast呢?
看源码:
private static InternalThreadLocalMap fastGet(FastThreadLocalThread thread) {
InternalThreadLocalMap threadLocalMap = thread.threadLocalMap();
if (threadLocalMap == null) {
thread.setThreadLocalMap(threadLocalMap = new InternalThreadLocalMap());
}
return threadLocalMap;
}
这一看我们就能知道它为什么fast了,因为它的InternalThreadLocalMap直接是这个thread的一个成员变量,直接取就可以。如果取不到就直接新建一个给它。
二、直接通过索引找到对象
那么我们又回到了get方法,得到map之后,把map传进去get,看源码:
/**
* Returns the current value for the specified thread local map.
* The specified thread local map must be for the current thread.
*/
@SuppressWarnings("unchecked")
public final V get(InternalThreadLocalMap threadLocalMap) {
Object v = threadLocalMap.indexedVariable(index);
if (v != InternalThreadLocalMap.UNSET) {
return (V) v;
}
return initialize(threadLocalMap);
}
这段代码的意思是,从threadLocalMap里面取对象,如果取到的值不是UNSET那么就返回,否则就通过initialize方法初始化一个对象。
先看indexedVariable(index)方法吧:
public Object indexedVariable(int index) {
Object[] lookup = indexedVariables;
return index < lookup.length? lookup[index] : UNSET;
}
就是在indexedVariables数组里面取出特定index的值。上一篇文章我们稍微提到了一个这个数组,这次我们分析一下。
这个数组是在这里初始化的:
UnpaddedInternalThreadLocalMap(Object[] indexedVariables) {
this.indexedVariables = indexedVariables;
}
然后到这里:
private InternalThreadLocalMap() {
super(newIndexedVariableTable());
}
然后newIndexedVariableTable:
private static Object[] newIndexedVariableTable() {
Object[] array = new Object[32];
Arrays.fill(array, UNSET);
return array;
}
这里很简单,就是创建一个初始化32的数组,数组里面的元素都是UNSET,这个UNSET是:
public static final Object UNSET = new Object();
注意这是一个静态的成员变量,所以在整个jvm进程里面,它都是不会变得。
直接通过索引获取对象就是我们比jdk原生的更加“fast”的一个很重要的原因,另外一个更加“fast”的原因是在我们获取InternalThreadLocalMap 的时候,FastThreadLocalThread直接通过成员变量获取,当然更加快了。
三、如果获取到的对象为UNSET,那就初始化对象
从initialize(threadLocalMap)这里进入
private V initialize(InternalThreadLocalMap threadLocalMap) {
V v = null;
try {
v = initialValue();
} catch (Exception e) {
PlatformDependent.throwException(e);
}
threadLocalMap.setIndexedVariable(index, v);
addToVariablesToRemove(threadLocalMap, this);
return v;
}
看initialValue是什么:
/**
* Returns the initial value for this thread-local variable.
*/
protected V initialValue() throws Exception {
return null;
}
默认实现的方法是返回null,我们当然也可以覆盖这个方法去实现自己的逻辑,例如我们《 netty源码阅读之性能优化工具类之FastThreadLocal的使用》这篇文章里面initialValue的实现方法为:
private static FastThreadLocal<Object> threadLocal = new FastThreadLocal<Object>() {
@Override
protected Object initialValue() {
return new Object();
}
};
然后有个threadLocalMap.setIndexedVariable(index, v);
/**
* @return {@code true} if and only if a new thread-local variable has been created
*/
public boolean setIndexedVariable(int index, Object value) {
Object[] lookup = indexedVariables;
if (index < lookup.length) {
Object oldValue = lookup[index];
lookup[index] = value;
return oldValue == UNSET;
} else {
expandIndexedVariableTableAndSet(index, value);
return true;
}
}
这里就是把我们初始化的值设置到map里面,下次我们要取得时候就能取到了。如果不够就扩容并且添加进去,如果旧值是UNSET就返回true。
最后还有一个addToVariablesToRemove(threadLocalMap, this);我们先通过名字记下来:
因为是初始化的值,所以以后是需要移除的。