Netty组件优化之FastThreadLocal

本文详细解析了Netty中的FastThreadLocal,它针对Java原生FastThreadLocal的性能问题进行了优化,通过使用InternalThreadLocalMap和FastThreadLocalThread,实现在线程间快速查找和赋值,提高效率。
摘要由CSDN通过智能技术生成

ThreadLocal:CSDNicon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/132995427

Netty中的FastThreadLocal是对Java中的FastThreadLocal的优化主要是为了解决ThreadLocal中线性查找 带来的性能下降同时实现快速查找和赋值

FastThreadLocal构建

   这里的index代表一个编号,从1开始增长,内部是一个原子变量的计数器。其内部有一个属性

private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();这段代码保证了
variablesToRemoveIndex的值为0

提前说一下InternalThreadLocalMap代替了Threadlocal中的ThreadlocalMap

其内部维持了一个数组每个数组的值默认位UNSET,UNSET其实就是一个Object对象

由于InternalThreadLocalMap和ThreadlocalMap没有继承关系所以不能直接赋值给Thread对象因此Netty通过继承Thread类,来完成增强。这个类就是FastThreadLocalThread

可以看到其内部主要是维护了一个InternalThreadLocalMap

public class ThreadLocal {
    private static final FastThreadLocal<String> fastThreadLocal = new FastThreadLocal(){
        @Override
        protected Object initialValue() throws Exception {
            return "NAN";
        }
    };
    public static void main(String[] args) {

        FastThreadLocalThread fastThreadLocalThread = new FastThreadLocalThread(()->{
            fastThreadLocal.set("nihao");
            System.out.println(fastThreadLocal.get());
        });
        fastThreadLocalThread.start();
    }
}

 接下来先从set方法看起

  public final void set(V value) {
        if (value != InternalThreadLocalMap.UNSET) {
            InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
            setKnownNotUnset(threadLocalMap, value);
        } else {
            remove();
        }
    }

set方法先判断value是否为UNSET,如果不是的话就调用get方法

  public static InternalThreadLocalMap get() {
        Thread thread = Thread.currentThread();
        if (thread instanceof FastThreadLocalThread) {
            return fastGet((FastThreadLocalThread) thread);
        } else {
            return slowGet();
        }
    }

get方法中如果是配合FastThreadLocalThread使用的话就会从中拿到InternalThreadLocalMap。

如果不是的话就调用slowGet方法,其原理就是使用原始的ThreadLocal,在通过ThreadlocalMap进行赋值。

但是这样效率明显降低了所以说FastThreadLocal只有配合FastThreadLocalThread才能发挥出高效率

此时已经那到了threadLocalMap,接下来就该进行赋值了

 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 boolean setIndexedVariable(int index, Object value) {
        Object[] lookup = indexedVariables;
        if (index < lookup.length) {
            Object oldValue = lookup[index];
            lookup[index] = value;
            return oldValue == UNSET;
        } else {
            expandIndexedVariableTableAndSet(index, value);
            return true;
        }
    }

可以看到首先是根据inex获取到数组中的值并把value重新赋值给对应的index,如果是初始化值UNSET的话返回true

赋值完毕后如果是第一次赋值返回true,紧接着执行addToVariablesToRemove方法

  private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {
        Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);
        Set<FastThreadLocal<?>> variablesToRemove;
        if (v == InternalThreadLocalMap.UNSET || v == null) {
            variablesToRemove = Collections.newSetFromMap(new IdentityHashMap<FastThreadLocal<?>, Boolean>());
            threadLocalMap.setIndexedVariable(variablesToRemoveIndex, variablesToRemove);
        } else {
            variablesToRemove = (Set<FastThreadLocal<?>>) v;
        }

        variablesToRemove.add(variable);
    }
variablesToRemoveIndex的值上边已经说过为0

这段代码告诉我们InternalThreadLocalMap维护的数组第一位为set集合,作用就是存储fastthreadlocal对象

接下来分析一下remove方法

这段代码的作用就是获得到FastThreadLocalMap,然后把对应index的值置为UNSET,并从set集合中移除FastThreadLocal。并调用onRemoval方法这个方法是留给使用者自己重写的可以做一些移除后的操作,比如连接关闭后进行资源释放

接下来看一下get方法

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

        return initialize(threadLocalMap);
    }

第一步先获得InternalThreadLocalMap,然后获得自己(FastThreadLocal)对应的值,进行判断如果说未设置值的话就调用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;
    }

其内部就是调用initialValue()方法进行赋值。此方法是交由使用者重写的,

例如

private static final FastThreadLocal<String> fastThreadLocal = new FastThreadLocal(){
        @Override
        protected Object initialValue() throws Exception {
            return "NAN";
        }
    };

可以看到为了避免空值我返回了一个字符串

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值