FastThreadLocal源码解析

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6


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设置值实现步骤:

  1. 判断是否InternalThreadLocalMap.UNSET,是则remove(ftl.set(InternalThreadLocalMap.UNSET)这样复制进入这步骤)
    1.1 将indexedVariables[index] = UNSET,调用onRemoval()移除堆、对外内存
  2. 否则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()以及相关后续流程

  1. fastGet()中会从indexedVariables数组中根据index获取数据,第一次会进行初始化

ftl资源回收机制

netty中对于ftl提供三种机制

  1. 用ftlt执行被FastThreadLocalRunnable wrap的Runnable任务,执行完会自动清理
  2. 显示调用remove()清理
  3. 每一个ftl注册一个Cleaner,当线程对象不强可达的时候,该Cleaner线程会将当前线程的当前ftl进行回收(netty-4.1.34已注释代码,不考虑)


阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6