netty源码阅读之性能优化工具类之FastThreadLocal的get方法实现

38 篇文章 1 订阅
33 篇文章 1 订阅

FastThreadLocal的get方法实现我们通过以下三部分分析:

1、获取ThreadLocalMap

2、直接通过索引找到对象

3、如果对象为空,那就初始化对象

 

我们从FastThreadLocal的get方法进入:

    /**
     * Returns the current value for the current thread
     */
    public final V get() {
        return get(InternalThreadLocalMap.get());
    }

一、获取ThreadLocalMap

InternalThreadLocalMap.get()就是我么这个过程,查看源码:

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

这里又fastGet和slowGet,slowGet就是线程不为FastThreadLocalThread的时候,我们先看slowGet方法的实现:

    private static InternalThreadLocalMap slowGet() {
        ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = UnpaddedInternalThreadLocalMap.slowThreadLocalMap;
        InternalThreadLocalMap ret = slowThreadLocalMap.get();
        if (ret == null) {
            ret = new InternalThreadLocalMap();
            slowThreadLocalMap.set(ret);
        }
        return ret;
    }

通过slowThreadLocalMap的get方法找出InternalThreadLocalMap,然后如果不存在就创建一个并放到slowThreadLocalMap里面,那么这个slowThreadLocalMap是什么的?


    static final ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap = new ThreadLocal<InternalThreadLocalMap>();

这个 slowThreadLocalMap是jdk原生的ThreadLocal里面的对象。

意思就是InternalThreadLocalMap是通过ThreadLocal的get方法里面把它取出来的,相对来说更加"slow",那么fast呢?

看源码:

    private static InternalThreadLocalMap fastGet(FastThreadLocalThread thread) {
        InternalThreadLocalMap threadLocalMap = thread.threadLocalMap();
        if (threadLocalMap == null) {
            thread.setThreadLocalMap(threadLocalMap = new InternalThreadLocalMap());
        }
        return threadLocalMap;
    }

这一看我们就能知道它为什么fast了,因为它的InternalThreadLocalMap直接是这个thread的一个成员变量,直接取就可以。如果取不到就直接新建一个给它。

 

二、直接通过索引找到对象

那么我们又回到了get方法,得到map之后,把map传进去get,看源码:

    /**
     * Returns the current value for the specified thread local map.
     * The specified thread local map must be for the current thread.
     */
    @SuppressWarnings("unchecked")
    public final V get(InternalThreadLocalMap threadLocalMap) {
        Object v = threadLocalMap.indexedVariable(index);
        if (v != InternalThreadLocalMap.UNSET) {
            return (V) v;
        }

        return initialize(threadLocalMap);
    }

这段代码的意思是,从threadLocalMap里面取对象,如果取到的值不是UNSET那么就返回,否则就通过initialize方法初始化一个对象。

先看indexedVariable(index)方法吧:

    public Object indexedVariable(int index) {
        Object[] lookup = indexedVariables;
        return index < lookup.length? lookup[index] : UNSET;
    }

 就是在indexedVariables数组里面取出特定index的值。上一篇文章我们稍微提到了一个这个数组,这次我们分析一下。

这个数组是在这里初始化的:


    UnpaddedInternalThreadLocalMap(Object[] indexedVariables) {
        this.indexedVariables = indexedVariables;
    }

然后到这里:


    private InternalThreadLocalMap() {
        super(newIndexedVariableTable());
    }

 然后newIndexedVariableTable:

    private static Object[] newIndexedVariableTable() {
        Object[] array = new Object[32];
        Arrays.fill(array, UNSET);
        return array;
    }

这里很简单,就是创建一个初始化32的数组,数组里面的元素都是UNSET,这个UNSET是:

public static final Object UNSET = new Object();

注意这是一个静态的成员变量,所以在整个jvm进程里面,它都是不会变得。

直接通过索引获取对象就是我们比jdk原生的更加“fast”的一个很重要的原因,另外一个更加“fast”的原因是在我们获取InternalThreadLocalMap 的时候,FastThreadLocalThread直接通过成员变量获取,当然更加快了。

 

三、如果获取到的对象为UNSET,那就初始化对象

从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是什么:


    /**
     * Returns the initial value for this thread-local variable.
     */
    protected V initialValue() throws Exception {
        return null;
    }

默认实现的方法是返回null,我们当然也可以覆盖这个方法去实现自己的逻辑,例如我们《 netty源码阅读之性能优化工具类之FastThreadLocal的使用》这篇文章里面initialValue的实现方法为:

    private static FastThreadLocal<Object> threadLocal = new FastThreadLocal<Object>() {
        @Override
        protected Object initialValue() {
            return new Object();
        }
    };

然后有个threadLocalMap.setIndexedVariable(index, v);

    /**
     * @return {@code true} if and only if a new thread-local variable has been created
     */
    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;
        }
    }

这里就是把我们初始化的值设置到map里面,下次我们要取得时候就能取到了。如果不够就扩容并且添加进去,如果旧值是UNSET就返回true。

最后还有一个addToVariablesToRemove(threadLocalMap, this);我们先通过名字记下来:

因为是初始化的值,所以以后是需要移除的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值