• 13.InternalThreadLocalMap


    UnpaddedInternalThreadLocalMap

    InternalThreadLocalMap继承自UnpaddedInternalThreadLocalMap所以先来看一下这个类.

    // 内部数据结构, 用于存储 Netty 和所有 FastThreadLocal 的线程局部变量.
    class UnpaddedInternalThreadLocalMap {
    
        // 如果在 Thread 中使用 FastThreadLocal, 则实际上使用 ThreadLocal 存放资源.
        static final ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = new ThreadLocal<InternalThreadLocalMap>();
    
        // 资源索引, 每一个 FastThreadLocal 对象都会有对应的ID, 即通过 nextIndex 自增得到.
        static final AtomicInteger nextIndex = new AtomicInteger();
    
        // 该值是在 InternalThreadLocalMap 构造方法中初始化, 数组默认大小 32, 并且数组中的所有值初始化为 InternalThreadLocalMap.UNSET.
        Object[] indexedVariables;
    
        // 下面这些变量在 InternalThreadLocalMap 中都会说道.
    
        // 调用深度
        int futureListenerStackDepth;
        int localChannelReaderStackDepth;
        Map<Class<?>, Boolean> handlerSharableCache;
        IntegerHolder counterHashCode;
        ThreadLocalRandom random;
        Map<Class<?>, TypeParameterMatcher> typeParameterMatcherGetCache;
        Map<Class<?>, Map<String, TypeParameterMatcher>> typeParameterMatcherFindCache;
    
        StringBuilder stringBuilder;
        // 在 charsetEncoderCache() 方法调用时如果为 null 就会创建 IdentityHashMap<Charset, CharsetEncoder> 实例.
        Map<Charset, CharsetEncoder> charsetEncoderCache;
        // 在 charsetDecoderCache() 方法调用时如果为 null 就会创建 IdentityHashMap<Charset, CharsetDecoder> 实例.
        Map<Charset, CharsetDecoder> charsetDecoderCache;
    
        // 调用 arrayList() 方法时会使用默认参数 8 来调用 arrayList(int) 方法, 
        // 如果 arrayList 属性为 null 则会创建 ArrayList<Object>(minCapacity) 实例;
        // 否则就会清空 arrayList 集合, 并调用 ensureCapacity 方法.
        ArrayList<Object> arrayList;
    
        UnpaddedInternalThreadLocalMap(Object[] indexedVariables) {
            this.indexedVariables = indexedVariables;
        }
    }
    

    InternalThreadLocalMap

    下面是一些比较重要的方法.

    public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {
    
        private static final InternalLogger logger = InternalLoggerFactory.getInstance(InternalThreadLocalMap.class);
    
        private static final int DEFAULT_ARRAY_LIST_INITIAL_CAPACITY = 8;
        private static final int STRING_BUILDER_INITIAL_SIZE;
        private static final int STRING_BUILDER_MAX_SIZE;
        private static final int HANDLER_SHARABLE_CACHE_INITIAL_CAPACITY = 4;
        private static final int INDEXED_VARIABLE_TABLE_INITIAL_SIZE = 32;
    
        public static final Object UNSET = new Object();
    
        private BitSet cleanerFlags;
    
        // 指定 stringBuilder 的初始化大小和最大大小.
        static {
            STRING_BUILDER_INITIAL_SIZE =
                    SystemPropertyUtil.getInt("io.netty.threadLocalMap.stringBuilder.initialSize", 1024);
            logger.debug("-Dio.netty.threadLocalMap.stringBuilder.initialSize: {}", STRING_BUILDER_INITIAL_SIZE);
    
            STRING_BUILDER_MAX_SIZE = SystemPropertyUtil.getInt("io.netty.threadLocalMap.stringBuilder.maxSize", 1024 * 4);
            logger.debug("-Dio.netty.threadLocalMap.stringBuilder.maxSize: {}", STRING_BUILDER_MAX_SIZE);
        }
    
        // 通过当前线程的类型获取线程值. 如果没有设置则返回 null.
        public static InternalThreadLocalMap getIfSet() {
            Thread thread = Thread.currentThread();
            if (thread instanceof FastThreadLocalThread) {
                // 由于 FastThreadLocalThread 中直接绑定了 InternalThreadLocalMap 实例, 所以可以直接获取.
                return ((FastThreadLocalThread) thread).threadLocalMap();
            }
            // 这里说明该线程不是 FastThreadLocalThread 类型或子类.
            // 通过 jdk 的 ThreadLocal 获取当前线程的值.
            return slowThreadLocalMap.get();
        }
    
        // 如果当前线程没有设置值, 则会创建一个新的 InternalThreadLocalMap 实例后设置并返回.
        public static InternalThreadLocalMap get() {
            Thread thread = Thread.currentThread();
            if (thread instanceof FastThreadLocalThread) {
                // 如果为 null 则会调用 FastThreadLocalThread#setThreadLocalMap 方法添加新实例.
                return fastGet((FastThreadLocalThread) thread);
            } else {
                // 如果为 null 则会调用 slowThreadLocalMap.set 方法添加新实例.
                return slowGet();
            }
        }
    
        //  fastGet 和 slowGet 代码就不复制了.
    
        // 删除当前线程的值, 没啥好说的就是删除 InternalThreadLocalMap 实例.
        public static void remove() {
            Thread thread = Thread.currentThread();
            if (thread instanceof FastThreadLocalThread) {
                ((FastThreadLocalThread) thread).setThreadLocalMap(null);
            } else {
                slowThreadLocalMap.remove();
            }
        }
    
        // 这里就是获取一个唯一ID.
        public static int nextVariableIndex() {
            // getAndIncrement 方法类似于 i++;
            int index = nextIndex.getAndIncrement();
            // 如果为负数说明已经 ++ 到超过 Int 类型的最大值(2147483647)
            if (index < 0) {
                nextIndex.decrementAndGet();
                throw new IllegalStateException("too many thread-local indexed variables");
            }
            return index;
        }
    
        // 当前 ID 的上一个.
        public static int lastVariableIndex() {
            return nextIndex.get() - 1;
        }
    
        // 根据 FastThreadLocal 初始化的 index, 确定其在资源列表中的位置, 后续查询资源就可以根据索引快速确定位置.
        public boolean setIndexedVariable(int index, Object value) {
            Object[] lookup = indexedVariables; // 当前的Object[]对象
            if (index < lookup.length) { // 检查当前的索引是否超过了Object数组的长度
                Object oldValue = lookup[index]; // 获取当前的值
                lookup[index] = value; // 将新值设置进去
                return oldValue == UNSET; // 判断之前的值是不是占位符,如果是则代表新增,不是代表更新
            } else {
                expandIndexedVariableTableAndSet(index, value); // 如果超过了,则需要进行扩容
                return true;
            }
        }
    
        private void expandIndexedVariableTableAndSet(int index, Object value) { // 扩容逻辑
            Object[] oldArray = indexedVariables; // 当前的Object数组
            final int oldCapacity = oldArray.length; // 当前的长度
            int newCapacity = index;  // index是这个FastThreadLocal对应的索引值
            newCapacity |= newCapacity >>>  1;
            newCapacity |= newCapacity >>>  2;
            newCapacity |= newCapacity >>>  4;
            newCapacity |= newCapacity >>>  8;
            newCapacity |= newCapacity >>> 16;
            newCapacity ++; // 这段其实也很有意思, 其实是为了计算新的数组的容量, 会变成下一个档位的2的次方大小, 
                            // 比如 1->2 2->4 3->4 4->8 5->8 6->8 7->8 8->16 18->32
    
            Object[] newArray = Arrays.copyOf(oldArray, newCapacity); // 将老的数据往新的数组进行拷贝
            Arrays.fill(newArray, oldCapacity, newArray.length, UNSET); // 将新的多出来的部分,设置占位符
            newArray[index] = value; // 将index对应的值设置完
            indexedVariables = newArray; // 将新的数组提升成Map中的indexedVariables
        }
    
        // 根据当前的 Thread 索引, 获取 Object.
        // 这个是一次性的, 对应的线程数据会被设置为 UNSET.
        public Object removeIndexedVariable(int index) {
            Object[] lookup = indexedVariables;
            if (index < lookup.length) {
                Object v = lookup[index];
                lookup[index] = UNSET;
                return v;
            } else {
                return UNSET;
            }
        }
    }
    

    InternalThreadLocalMap 使用数组来管理每个线程中的变量.

    参考文章

    Netty源码分析--FastThreadLocal分析(十)

  • 相关阅读:
    待写
    让一个小div在另一个大div里面 垂直居中的四种方法
    20 个有用的 SVG 工具,提供更好的图像处理
    php原理简述
    Apache 打开网页的时候等待时间过长的解决方案
    TCP协议中的三次握手和四次挥手(图解)
    apache 各平台进程线程模块解析
    浅谈移动Web开发(上):深入概念
    响应式布局
    jQuery Mobile 入门教程
  • 原文地址:https://www.cnblogs.com/scikstack/p/13534005.html
Copyright © 2020-2023  润新知