FastThreadLocal的set方法实现我们从以下三点分析:
1、获取ThreadLocalMap
2、直接通过索引set对象
3、如果需要remove对象,那就remove
我们还是从set方法源码开始:
/**
* Set the value for the current thread.
*/
public final void set(V value) {
if (value != InternalThreadLocalMap.UNSET) {
set(InternalThreadLocalMap.get(), value);
} else {
remove();
}
}
一、获取ThreadLocalMap
获取ThreadLocalMap的方法还是和之前的一样调用这个方法InternalThreadLocalMap.get(),不多解释了,可以看上一篇文章。
二、直接通过索引set对象
那么我们看set的源码:
/**
* Set the value for the specified thread local map. The specified thread local map must be for the current thread.
*/
public final void set(InternalThreadLocalMap threadLocalMap, V value) {
if (value != InternalThreadLocalMap.UNSET) {
if (threadLocalMap.setIndexedVariable(index, value)) {
addToVariablesToRemove(threadLocalMap, this);
}
} else {
remove(threadLocalMap);
}
}
如果设置进来的值不是UNSET那么久把值设置进去,
* @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;
}
}
设置值还是只要把对象放到特定的索引位置就可以了,注意我们还是返回了 oldValue==UNSET。也就是,我们返回了之前的值是否为unset,返回之后,如果为unset,那么就要调用addToVariablesToRemove。
三、如果需要remove对象,那就remove
我们之前看到了一个这个remove(threadLocalMap);
看源码:
/**
* Sets the value to uninitialized for the specified thread local map;
* a proceeding call to get() will trigger a call to initialValue().
* The specified thread local map must be for the current thread.
*/
@SuppressWarnings("unchecked")
public final void remove(InternalThreadLocalMap threadLocalMap) {
if (threadLocalMap == null) {
return;
}
Object v = threadLocalMap.removeIndexedVariable(index);
removeFromVariablesToRemove(threadLocalMap, this);
if (v != InternalThreadLocalMap.UNSET) {
try {
onRemoval((V) v);
} catch (Exception e) {
PlatformDependent.throwException(e);
}
}
}
看这个removeIndexedVariable方法:
public Object removeIndexedVariable(int index) {
Object[] lookup = indexedVariables;
if (index < lookup.length) {
Object v = lookup[index];
lookup[index] = UNSET;
return v;
} else {
return UNSET;
}
}
其实很简单,就是把索引所在位置的对象设置为UNSET对象。
还有一个removeFromVariablesToRemove(threadLocalMap, this);和前面的addToVariablesToRemove相对应。
目前我们知道有两种情况需要addToVariables的:
1、在set之后,set之前老值为UNSAFE的。
2、在调用get之后,没有对象然后调用initial方法给赋值的再返回的。
有一种情况需要removeFromVariables的:
1、在remove也就是设置一个index的值为UNSET之后。
最后一个:
if (v != InternalThreadLocalMap.UNSET) {
try {
onRemoval((V) v);
} catch (Exception e) {
PlatformDependent.throwException(e);
}
}
如果移除的对象是用户设置进去的,那么就调用onRemoval方法,这个方法可以在用户代码里面覆盖,例如:
private static FastThreadLocal<Object> threadLocal = new FastThreadLocal<Object>() {
@Override
protected Object initialValue() {
return new Object();
}
@Override
protected void onRemoval(Object value) throws Exception {
System.out.println("onRemoval");
}
};
那么当我们移除这个数据的时候,我们就知道被移除了。