关于程序员:Netty源码FastThreadLocal源码

38次阅读

共计 7529 个字符,预计需要花费 19 分钟才能阅读完成。

承接上文,这篇次要就剖析 FastThreadLocal 顺带剖析下相干内容

what

既然又了 ThreadLocal 为什么 Netty 又创立了一个 FastThreadLocal 呢,首先,先看下 FastThreadLocal 的正文,类正文下面阐明了。简述一下

  1. 通过 FastThreadLocalThread 拜访会更快
  2. 取代了 Hash 映射,应用常量
  3. 解决频繁拜访的场景

    A special variant of  ThreadLocal that yields higher access performance when accessed from a FastThreadLocalThread.
    
    ThreadLocal 的一种非凡变体,当从 FastThreadLocalThread 进行拜访时,会产生更高的拜访性能。Internally, a  FastThreadLocal uses a constant index in an array, instead of using hash code and hash table, to look for a variable.  Although seemingly very subtle, it yields slight performance advantage over using a hash  table, and it is useful when accessed frequently.
    
     在外部,FastThreadLocal 应用数组中的常量索引,而不是应用哈希代码和哈希表来查找变量。尽管看起来很奥妙,但它比应用哈希表产生了轻微的性能劣势,并且在频繁拜访时十分有用。To take advantage of this thread-local variable, your thread must be a FastThreadLocalThread or its subtype.By default, all threads created by DefaultThreadFactory are  FastThreadLocalThread due to this reason.
    
     要利用此线程局部变量,你的线程必须是 FastThreadLocalThread 或其子类型。因为这个起因,默认状况下,DefaultThreadFactory 创立的所有线程都是 FastThreadLocalThread。Note that the fast path is only possible on threads that extend  FastThreadLocalThread, because it requires a special field to store the necessary state.  An access by any other kind of thread falls back to a regular link ThreadLocal.
    
     请留神,疾速门路仅实用于扩大 FastThreadLocalThread 的线程,因为它须要一个非凡字段来存储必要的状态。任何其余类型的线程的拜访都会回退到惯例链接 ThreadLocal。

Detail

简述

上一篇看过了,这里就很容易了,也是将存储对象放入到线程中,这里对象就简略粗犷了,没有通过 Entry 了, 而是间接通过 Object[] 数组, 那么是怎么定位的呢,它是通过 private static final AtomicInteger nextIndex = new AtomicInteger(); 来实现的,每次 FastThreadLocal 创立都会取得惟一的值,自增,防止了哈希碰撞。

初始化会全副设置成一个 Object 这样就能够晓得 FastThreadLocal 第一次塞值的中央了,第一次塞值会塞入到 variablesToRemoveIndex 这个地位,这个地位比拟特地,放的全是FastThreadLocal,当线程执行结束的时候,会比拟不便的革除援用。

先记住一个大略,上面会有具体的剖析,这里呢先记住个大略,上面会一一剖析的

set

    public final void set(V value) {if (value != InternalThreadLocalMap.UNSET) {
            //1.1
            InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
            //1.2
            setKnownNotUnset(threadLocalMap, value);
        } else {remove();
        }
    }
    
    //1.1 InternalThreadLocalMap
    public static InternalThreadLocalMap get() {Thread thread = Thread.currentThread();
        if (thread instanceof FastThreadLocalThread) {
            //2.1
            return fastGet((FastThreadLocalThread) thread);
        } else {return slowGet();
        }
    }
    
    //2.1
    private static InternalThreadLocalMap fastGet(FastThreadLocalThread thread) {
        // 同样是存储在 FastThreadLocalThread 中
        InternalThreadLocalMap threadLocalMap = thread.threadLocalMap();
        // 如果没有回创立一个
        if (threadLocalMap == null) {
            //3.1
            thread.setThreadLocalMap(threadLocalMap = new InternalThreadLocalMap());
        }
        return threadLocalMap;
    }
    
    //3.1
    private InternalThreadLocalMap() {indexedVariables = newIndexedVariableTable();
    }

    private static Object[] newIndexedVariableTable() {
        //INDEXED_VARIABLE_TABLE_INITIAL_SIZE:32
        Object[] array = new Object[INDEXED_VARIABLE_TABLE_INITIAL_SIZE];
        //public static final Object UNSET = new Object();
        Arrays.fill(array, UNSET);
        return array;
    }
    
    //1.2
    private void setKnownNotUnset(InternalThreadLocalMap threadLocalMap, V value) {
        //2.2 
        if (threadLocalMap.setIndexedVariable(index, value)) {
            //3.2
            addToVariablesToRemove(threadLocalMap, this);
        }
    }
    
    //2.2
    public boolean setIndexedVariable(int index, Object value) {// 初始化创立的的 Object[]数组,初始化的时候全是 UNSET
        Object[] lookup = indexedVariables;
        // 这个 index 是 FastThreadLocal 初始化的时候创立的时候就会赋值的,这个前面再剖析
        // 这里阐明不须要扩容
        if (index < lookup.length) {
            // 老值
            Object oldValue = lookup[index];
            // 设置新值
            lookup[index] = value;
            // 比对老值是否等于 UNSET
            return oldValue == UNSET;
        } else {
            //4.1 扩容
            expandIndexedVariableTableAndSet(index, value);
            return true;
        }
    }
    
    //3.2
    private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {//private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();
        // 返回 threadLocalMap,variablesToRemoveIndex 地位的值
        Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
        Set<FastThreadLocal<?>> variablesToRemove;
        if (v == InternalThreadLocalMap.UNSET || v == null) {variablesToRemove = Collections.newSetFromMap(new IdentityHashMap<FastThreadLocal<?>, Boolean>());
            // 往 threadLocalMap[variablesToRemoveIndex], 设置一个 Set
            threadLocalMap.setIndexedVariable(variablesToRemoveIndex, variablesToRemove);
        } else {
            // 获取该 set
            variablesToRemove = (Set<FastThreadLocal<?>>) v;
        }
        // 将以后 ThreadLocal 增加进该 set
        variablesToRemove.add(variable);
    }
    

扩容

它一大串或就是保障最高位开始前面全都为 1,+ 1 后就是 2 的倍数,

而后扩容,把 index 塞到它应该在的地位上

    private void expandIndexedVariableTableAndSet(int index, Object value) {Object[] oldArray = indexedVariables;
        final int oldCapacity = oldArray.length;
        int newCapacity = index;
        newCapacity |= newCapacity >>>  1;
        newCapacity |= newCapacity >>>  2;
        newCapacity |= newCapacity >>>  4;
        newCapacity |= newCapacity >>>  8;
        newCapacity |= newCapacity >>> 16;
        newCapacity ++;

        Object[] newArray = Arrays.copyOf(oldArray, newCapacity);
        Arrays.fill(newArray, oldCapacity, newArray.length, UNSET);
        newArray[index] = value;
        indexedVariables = newArray;
    }

初始化

上面这边是 2 个初始化变量,index,每次创立的时候,会顺次递增,variablesToRemoveIndex就是所有 FastThreadLocal 专用啦。

public class FastThreadLocal<V> {private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();

    
    private final int index;

    public FastThreadLocal() {index = InternalThreadLocalMap.nextVariableIndex();
    }
}  

public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {private static final AtomicInteger nextIndex = new AtomicInteger();

    public static int nextVariableIndex() {int index = nextIndex.getAndIncrement();
        if (index < 0) {nextIndex.decrementAndGet();
            throw new IllegalStateException("too many thread-local indexed variables");
        }
        return index;
    }
}    

销毁

这里次要看一下 variablesToRemoveIndex 的用法了,能够参考 FastThreadLocalRunnable 在执行完结后会调用 removeAll 革除援用

final class FastThreadLocalRunnable implements Runnable {
    private final Runnable runnable;

    private FastThreadLocalRunnable(Runnable runnable) {this.runnable = ObjectUtil.checkNotNull(runnable, "runnable");
    }

    @Override
    public void run() {
        try {runnable.run();
        } finally {FastThreadLocal.removeAll();
        }
    }
}    
    public static void removeAll() {InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.getIfSet();
        if (threadLocalMap == null) {return;}

        try {Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
            if (v != null && v != InternalThreadLocalMap.UNSET) {@SuppressWarnings("unchecked")
                //FastThreadLocal 汇合
                Set<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;
                
                FastThreadLocal<?>[] variablesToRemoveArray =
                        variablesToRemove.toArray(new FastThreadLocal[0]);
                // 遍历所有的 FastThreadLocal    
                for (FastThreadLocal<?> tlv: variablesToRemoveArray) {
                    //
                    tlv.remove(threadLocalMap);
                }
            }
        } finally {InternalThreadLocalMap.remove();
        }
    }
    
    public final void remove(InternalThreadLocalMap threadLocalMap) {if (threadLocalMap == null) {return;}
        //1.1
        Object v = threadLocalMap.removeIndexedVariable(index);
        //1.2
        removeFromVariablesToRemove(threadLocalMap, this);
        // 没有删除的状况
        if (v != InternalThreadLocalMap.UNSET) {
            try {
                // 预留模板办法,自定义实现
                onRemoval((V) v);
            } catch (Exception e) {PlatformDependent.throwException(e);
            }
        }
    }
    //1.1 去援用,赋值为 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;}
    }
    
    //1.2
    private static void removeFromVariablesToRemove(InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);

        if (v == InternalThreadLocalMap.UNSET || v == null) {return;}

        @SuppressWarnings("unchecked")
        Set<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;
        //set 中去掉这个 FastThreadLocal
        variablesToRemove.remove(variable);
    }

get

这个没啥好说的,一看就懂了

    
    public final V get() {InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
        Object v = threadLocalMap.indexedVariable(index);
        if (v != InternalThreadLocalMap.UNSET) {return (V) v;
        }

        return 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;
    }

总结

FastThreadLocal次要外围我感觉就是通过 index 来取代哈希运算了,然而这样可能带来一个小问题,别频繁创立,why 就不剖析了,正文写的很分明了,就是为了速度,over~~

本文由 mdnice 多平台公布

正文完
 0