《Netty核心代码解析》FastThreadLocal

系列FastThreadLocal目录



前言

Netty作为一个高性能的网络框架,针对自己的业务实现了一些API,比如FastThreadLocalThread和FastThreadLocal等。用来实现Pooled池化内存。


# 一、FastThreadLocalThread Netty自定义了Thread类,用于存储自定义的ThreadLocalMap。
public class FastThreadLocalThread extends Thread {
    // This will be set to true if we have a chance to wrap the Runnable.
    private final boolean cleanupFastThreadLocals;

    // 内部的ThreadLocalMap,用于存储ThreadLocal
    private InternalThreadLocalMap threadLocalMap;

二、InternalThreadLocalMap

public final class InternalThreadLocalMap extends UnpaddedInternalThreadLocalMap {

    private static final InternalLogger logger = InternalLoggerFactory.getInstance(InternalThreadLocalMap.class);

    // 内嵌了jdk原生的ThreadLocal
    private static final ThreadLocal<InternalThreadLocalMap> slowThreadLocalMap =
            new ThreadLocal<InternalThreadLocalMap>();

    // 原子类,实现对indexedVariables数组桶位置的记录
    private static final AtomicInteger nextIndex = new AtomicInteger();


    // Map的HashTable数组的初始长度
    private static final int INDEXED_VARIABLE_TABLE_INITIAL_SIZE = 32;
	
	// 单例,空对象,用来填充HashTable
    public static final Object UNSET = new Object();

    // ThreadLocal的存储数组
    private Object[] indexedVariables; 

     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 {
            // 当插入位置的索引大于HashTable的长度时,就开始扩容
            expandIndexedVariableTableAndSet(index, value);
            return true;
        }
    }

    // 扩容
    private void expandIndexedVariableTableAndSet(int index, Object value) {
        Object[] oldArray = indexedVariables;
        final int oldCapacity = oldArray.length;
        int newCapacity = index;

        // 这个算法是按照当前的索引扩容到 2*newCapacity - 1
        newCapacity |= newCapacity >>>  1;
        newCapacity |= newCapacity >>>  2;
        newCapacity |= newCapacity >>>  4;
        newCapacity |= newCapacity >>>  8;
        newCapacity |= newCapacity >>> 16;

        // 2*newCapacity - 1 + 1 其实是扩容2倍。
        newCapacity ++;
        // 将原数组拷贝到新的数组。
        Object[] newArray = Arrays.copyOf(oldArray, newCapacity);
        // 将拷贝不满的地方进行初始化
        Arrays.fill(newArray, oldCapacity, newArray.length, UNSET);
        // 然后将值进行添加
        newArray[index] = value;
        indexedVariables = newArray;
    }
    
    // 根据索引拿到指定的ThreadLocal,因为这个Map是存储在线程中的,所以不存在线程安全问题
    public Object indexedVariable(int index) {
        Object[] lookup = indexedVariables;
        return index < lookup.length? lookup[index] : UNSET;
    }

三、FastThreadLocal

Netty的作者嫌jdk原生的ThreadLoca在每次调用get方法的时候都得计算一次hash,所以将put进Map的时候,将hash桶的索引记录在了成员变量中。

1、ThreadLocal

public T get() {
       Thread t = Thread.currentThread();
       ThreadLocalMap map = getMap(t);
       if (map != null) {
           ThreadLocalMap.Entry e = map.getEntry(this);
           if (e != null) {
               @SuppressWarnings("unchecked")
               T result = (T)e.value;
               return result;
           }
       }
       return setInitialValue();
   }
   
	private Entry getEntry(ThreadLocal<?> key) {
		/// 这里的一个hash
        int i = key.threadLocalHashCode & (table.length - 1);
        Entry e = table[i];
        if (e != null && e.get() == key)
            return e;
        else
            return getEntryAfterMiss(key, i, e);
	 }

2、FastThreadLocal源码

    // 重点索引
    private final int index;

    public FastThreadLocal() {
    	// 调用InternalThreadLocalMap的静态方法,拿到原子类所记录的当前插入的索引;因为只要是创建过的FastThreadLocal,肯定已经存到map了
        index = InternalThreadLocalMap.nextVariableIndex();
    }

    /**
     * Returns the current value for the current thread
     */
    @SuppressWarnings("unchecked")
    public final V get() {
    	// 
        InternalThreadLocalMap threadLocalMap = InternalThreadLocalMap.get();
        // 根据InternalThreadLocalMap和当前FastThreadLocal记录的索引拿到存的ThreadLocal的值
        Object v = threadLocalMap.indexedVariable(index);
        if (v != InternalThreadLocalMap.UNSET) {
            return (V) v;
        }

        return initialize(threadLocalMap);
    }

三、PoolThreadLocalCache

PoolThreadLocalCache类是用在池化内存分配的时候的ThreadLocal(PoolThreadLocalCache 继承FastThreadLocal)类,其与PoolThreadCache组成键值对存放在FastThread的InternalThreadLocalMap中。重点是重写了initialValue方法,第一次想从ThreadLocal中获取缓存的时候,发现为空,就会调用重写的initialValue方法进行初始化PoolThreadCache。

final class PoolThreadLocalCache extends FastThreadLocal<PoolThreadCache> {
        private final boolean useCacheForAllThreads;

        PoolThreadLocalCache(boolean useCacheForAllThreads) {
            this.useCacheForAllThreads = useCacheForAllThreads;
        }


        // 重写了父类的initialValue方法,会回调这个方法,进行当前Thread操作池化分配时的缓存ThreadLocal
        @Override
        protected synchronized PoolThreadCache initialValue() {
            final PoolArena<byte[]> heapArena = leastUsedArena(heapArenas);
            final PoolArena<ByteBuffer> directArena = leastUsedArena(directArenas);

            final Thread current = Thread.currentThread();
            if (useCacheForAllThreads || current instanceof FastThreadLocalThread) {
                final PoolThreadCache cache = new PoolThreadCache(
                        heapArena, directArena, smallCacheSize, normalCacheSize,
                        DEFAULT_MAX_CACHED_BUFFER_CAPACITY, DEFAULT_CACHE_TRIM_INTERVAL);

                if (DEFAULT_CACHE_TRIM_INTERVAL_MILLIS > 0) {
                    final EventExecutor executor = ThreadExecutorMap.currentExecutor();
                    if (executor != null) {
                        executor.scheduleAtFixedRate(trimTask, DEFAULT_CACHE_TRIM_INTERVAL_MILLIS,
                                DEFAULT_CACHE_TRIM_INTERVAL_MILLIS, TimeUnit.MILLISECONDS);
                    }
                }
                return cache;
            }
            // No caching so just use 0 as sizes.
            return new PoolThreadCache(heapArena, directArena, 0, 0, 0, 0);
        }
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值