浅析FastThreadLocal

FastThreadLocal是啥?
它本质上还是一个ThreadLocal。但从它的名称,可以知道它比普通的ThrealLocal要快。

一.构造函数

实例FastThreadLocal时,获取一个在InternalThreadLocalMap中的索引标识。
InternalThreadLocalMap就是一个挂羊头卖狗肉的,内部使用一个数组存数据。

	// 用于标志在InternalThreadLocalMap的位置
	private final int index;

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

二.set

先来看看set方法

	public final void set(V value) {
		// InternalThreadLocalMap.UNSET 是初始化时默认添加的对象
        if (value != InternalThreadLocalMap.UNSET) {
        	// 这个是核心优化点
            InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
            setKnownNotUnset(threadLocalMap, value);
        } else {
            remove();
        }
    }
1. InternalThreadLocalMap.get()

InternalThreadLocalMap.get()是个关键点,这里进行了快慢区分。

	public static InternalThreadLocalMap get() {
        Thread thread = Thread.currentThread();
        // 这里表明了FastThreadLocal要和FastThreadLocalThread搭配使用才高效
        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;
    }
    

FastThreadLocalThread为什么快呢
因为普通的ThreadLocal获取对象,首先要进行hash计算,然后处理hash冲突问题。而FastThreadLocalThread则不需要这个,对象直接作为其属性存储。

继续看实例化InternalThreadLocalMap。

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

    private static Object[] newIndexedVariableTable() {
        Object[] array = new Object[32];
        // 默认填充了UNSET对象,与set时的判断对应
        Arrays.fill(array, UNSET);
        return array;
    }
2.setKnownNotUnset

回到set方法,继续看setKnownNotUnset的操作。

 private boolean setKnownNotUnset(InternalThreadLocalMap threadLocalMap, V value) {
 		// 将数据存入threadLocalMap中
        if (threadLocalMap.setIndexedVariable(index, value)) {
        	// 走到这里表明是插入了新的线程数据
            addToVariablesToRemove(threadLocalMap, this);
            return true;
        }
        return false;
    }

	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;
        }
    }
	
    private void expandIndexedVariableTableAndSet(int index, Object value) {
        Object[] oldArray = indexedVariables;
        final int oldCapacity = oldArray.length;
        int newCapacity = index;
        // 扩容两倍,与HashMap里面的扩容类似
        newCapacity |= newCapacity >>>  1;
        newCapacity |= newCapacity >>>  2;
        newCapacity |= newCapacity >>>  4;
        newCapacity |= newCapacity >>>  8;
        newCapacity |= newCapacity >>> 16;
        newCapacity ++;

        Object[] newArray = Arrays.copyOf(oldArray, newCapacity);
        // 扩容的数据都填充UNSET对象
        Arrays.fill(newArray, oldCapacity, newArray.length, UNSET);
        newArray[index] = value;
        indexedVariables = newArray;
    }

3.addToVariablesToRemove

通过源码可知,addToVariablesToRemove这个操作是存放新加入的FastThreadLocal对象。

// 这里的static,final表明了variablesToRemoveIndex初始化时设置好,故而一直为0
private static final int variablesToRemoveIndex = InternalThreadLocalMap.nextVariableIndex();

 private static void addToVariablesToRemove(InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {
 		// 这里获取threadLocalMap索引为0的数据
        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;
        }
		// 将新加入的FastThreadLocal存入
        variablesToRemove.add(variable);
    }

三.remove

remove比较简单,主要做了两个操作:

  • 重置threadLocalMap中对应的索引数据
  • 移除threadLocalMap索引为0的数据中包含的当前FastThreadLocal
	public final void remove() {
		// InternalThreadLocalMap.getIfSet()获取InternalThreadLocalMap对象与前文类似
        remove(InternalThreadLocalMap.getIfSet());
    }

	public final void remove(InternalThreadLocalMap threadLocalMap) {
        ...
        // 设置index对应数据为默认值
        Object v = threadLocalMap.removeIndexedVariable(index);
        // 移除当前的FastThreadLocal
        removeFromVariablesToRemove(threadLocalMap, this);
		...
    }
	
	public Object removeIndexedVariable(int index) {
        Object[] lookup = indexedVariables;
        if (index < lookup.length) {
            Object v = lookup[index];
            // 重置index对应值为默认值
            lookup[index] = UNSET;
            return v;
        } else {
            return UNSET;
        }
    }

	 private static void removeFromVariablesToRemove(
            InternalThreadLocalMap threadLocalMap, FastThreadLocal<?> variable) {
		// 获取索引0位置的数据
        Object v = threadLocalMap.indexedVariable(variablesToRemoveIndex);

        if (v == InternalThreadLocalMap.UNSET || v == null) {
            return;
        }
		// 执行set的remove操作
        Set<FastThreadLocal<?>> variablesToRemove = (Set<FastThreadLocal<?>>) v;
        variablesToRemove.remove(variable);
    }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值