源码分析-FastThreadLocal为什么能比ThreadLocal快

本文详细分析了FastThreadLocal与ThreadLocal的区别,指出FastThreadLocal通过维护一个索引来直接定位值,从而提高效率。FastThreadLocal在FastThreadLocalThread中使用,避免了哈希计算,提升了性能。但要发挥其优势,线程必须是FastThreadLocalThread类型。
摘要由CSDN通过智能技术生成

ThreadLocal与FastThreadLocal区别

ThreadLocal:
在这里插入图片描述

FastThreadLocal:
在这里插入图片描述

ThreadLocal和FastThreadLocal 在上图中结果几乎是差不多的,区别主要如下:

1.ThreadLocal的通过key计算Hash值找到对应的Entry,找到value

.对此不清楚可查看源码分析-ThreadLocal

2.而FastThreadLocal则是维护了一个Index,直接就通过这个Index找到对应的value.这就是FastThreadLocal为什么能比ThreadLocal快的主要原因

FastThreadLocal源码

1.首先要了解一个类,FastThreadLocalThread里面有一个InternalThreadLocalMap

public class FastThreadLocalThread extends Thread {
    private InternalThreadLocalMap threadLocalMap;
}

2.看看FasThreadLocal的部分源码 (主要是set方法相关)

public class FastThreadLocal<V> {
    //3.维护index,这个index代表着当前FastThreadLocal对象在InternalThreadLocalMap的indexedVariables的位置
    private final int index;
    public FastThreadLocal() {
        //4.nextVariableIndex()方法就是AtomicInteger.getAndIncrement(),相当于一个自增Id
        //所以每次new一个FastThreadLocal,就可以得到一个属于当前对象的Id
        index = InternalThreadLocalMap.nextVariableIndex();
    }
    public final void set(V value) {
        //Object UNSET = new Object(); ///InternalThreadLocalMap.UNSET是一个对象,用来填充未设置值的位置
        // 即InternalThreadLocalMap初始化后,里面的成员变量 Object[] indexedVariables 会全部用 InternalThreadLocalMap.UNSET
        //这个对象先填充,代表着未设置值。
        if (value != InternalThreadLocalMap.UNSET) {
            //1.获取当前线程的InternalThreadLocalMap 
            InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
            setKnownNotUnset(threadLocalMap, value);
        } else {
            remove();
        }
        
        private void setKnownNotUnset(InternalThreadLocalMap threadLocalMap, V value) {
            //2.直接就通过Index,将值设置进去,这里就是与逻辑上与ThreadLocal最主要的区别
            if (threadLocalMap.setIndexedVariable(index, value)) {
                addToVariablesToRemove(threadLocalMap, this);
            }
        }
    }
}

3. InternalThreadLocalMap.get()部分源码如下

public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {
    public static InternalThreadLocalMap get() {
        Thread thread = Thread.currentThread();
        //当前线程为FastThreadLocalThread才可以调用fastGet, 用得不对性能反而比不上ThreadLocal的原因
        if (thread instanceof FastThreadLocalThread) {
            return fastGet((FastThreadLocalThread) thread);
        } else {
            return slowGet();
        }
    }

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

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

4.看看FasThreadLocal的get方法

public final V get() {
    InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
    //直接就通过index获取值
    Object v = threadLocalMap.indexedVariable(index);
    if (v != InternalThreadLocalMap.UNSET) {
        //已经设置值, 直接返回
        return (V) v;
    }
    //未设置值,返回一个null
    return initialize(threadLocalMap);
}
 public Object indexedVariable(int index) {
    Object[] lookup = indexedVariables;
    return index < lookup.length? lookup[index] : UNSET;
}

5.InternalThreadLocalMap indexedVariables 填充 UNSET,代表着未设置值。

public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {
   private InternalThreadLocalMap() {
        super(newIndexedVariableTable());
    }

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

6.想发挥FastThreadLocal的性能优势,线程一定要用FastThreadLocalThread

public class FastThreadLocalTest {

    static FastThreadLocal<Integer> fastThreadLocal1 = new FastThreadLocal<>();

    static FastThreadLocal<Integer> fastThreadLocal2 = new FastThreadLocal<>();

    public static void main(String[] args) {

        FastThreadLocalThread threadA = new FastThreadLocalThread(new Runnable() {
            @Override
            public void run() {
                fastThreadLocal1.set(1);
                fastThreadLocal2.set(2);
            }
        });

        FastThreadLocalThread threadB = new FastThreadLocalThread(new Runnable() {
            @Override
            public void run() {
                fastThreadLocal1.set(3);
                fastThreadLocal2.set(4);
            }
        });
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值