「Netty源码」FastThreadLocal源码

承接上文,这篇主要就分析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

简述

alt

上一篇看过了,这里就很容易了,也是将存储对象放入到线程中,这里对象就简单粗暴了,没有通过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的倍数, alt 然后扩容,把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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值