Netty为什么要用自己的FastThreadLocal?
threadLocal Hash冲突,检索时间长。Netty自己定义的fastThreadLocal用的是数组,直接数组下标检索快。下面以ftl作为FastThreadLocal的简称
例子
ftl只有在FastThreadLocalThread线程中运行才生效,不然会走SlowGet模式(jdk threadLocal方式)
public class Demo {
public static void main(String[] args) throws Exception {
FastThreadLocalThread fastThreadLocalThread = new FastThreadLocalThread(() -> {
FastThreadLocal<Integer> ftl = new FastThreadLocal<>();
ftl.set(1);
System.out.println(ftl.get());
}
);
fastThreadLocalThread.start();
fastThreadLocalThread.join();
System.out.println("print main thread");
}
}
原理解析
ftl涉及主要属性
// 1. 用于slowGet()的threadLocal
static final ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = new ThreadLocal<InternalThreadLocalMap>();
// 2. 用于fastGet()。nextIndex: 用于记录当前下标;indexedVariables: fastGet()模式下用 数组Object[] 替代hash
static final AtomicInteger nextIndex = new AtomicInteger();
Object[] indexedVariables;
ftl set设置值实现步骤:
- 判断是否InternalThreadLocalMap.UNSET,是则remove(ftl.set(InternalThreadLocalMap.UNSET)这样复制进入这步骤)
1.1 将indexedVariables[index] = UNSET,调用onRemoval()移除堆、对外内存 - 否则InternalThreadLocalMap.get()获取
2.1 判断 thread instanceof FastThreadLocalThread 是否成立? 成立则fastGet()
- 不存在会初始化一个Object[] indexedVariables(默认值均为UNSET),
并根据index设置值,如果index大于indexedVariables.length则扩容(线程index是private final int index;线程私有)
- 扩容:Arrays.copyOf拷贝,Arrays.fill填充
2.2 否则slowGet()。降级为JDK threadLocal,这个就不分析了
class Xxxx {
public final void set(V value) {
if (value != InternalThreadLocalMap.UNSET) {
InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
setKnownNotUnset(threadLocalMap, value);
} else {
remove();
}
}
private void setKnownNotUnset(InternalThreadLocalMap threadLocalMap, V value) {
if (threadLocalMap.setIndexedVariable(index, value)) {// 数组形式设置
addToVariablesToRemove(threadLocalMap, this);
}
}
public static InternalThreadLocalMap get() {
Thread thread = Thread.currentThread();
if (thread instanceof FastThreadLocalThread) {// ftl快的模式
return fastGet((FastThreadLocalThread) thread);
} else {// ftl慢的模式
return slowGet();
}
}
}
ftl get获取值实现步骤(简单很多):
同样会判断是否fastGet()还是slowGet(),slowGet走threadLocal不讨论,一下只讨论fastGet()以及相关后续流程
- fastGet()中会从indexedVariables数组中根据index获取数据,第一次会进行初始化
ftl资源回收机制
netty中对于ftl提供三种机制
- 用ftlt执行被FastThreadLocalRunnable wrap的Runnable任务,执行完会自动清理
- 显示调用remove()清理
- 每一个ftl注册一个Cleaner,当线程对象不强可达的时候,该Cleaner线程会将当前线程的当前ftl进行回收(netty-4.1.34已注释代码,不考虑)