1. 程式人生 > >netty原始碼閱讀之效能優化工具類之Recycler獲取物件

netty原始碼閱讀之效能優化工具類之Recycler獲取物件

 Recycler獲取物件主要分為以下幾部分:

1、獲取當前執行緒的Stack

2、從Stack裡面彈出物件

3、如果彈出物件為空,那就建立物件並且繫結到Stack裡面

我們從Recycler的get方法進入,就是這個原始碼:

    @SuppressWarnings("unchecked")
    public final T get() {
        if (maxCapacityPerThread == 0) {
            return newObject((Handle<T>) NOOP_HANDLE);
        }
        Stack<T> stack = threadLocal.get();
        DefaultHandle<T> handle = stack.pop();
        if (handle == null) {
            handle = stack.newHandle();
            handle.value = newObject(handle);
        }
        return (T) handle.value;
    }

首先看maxCapacityPerThread==0這個分支,看NOOP_HANDLE這個原始碼:

    @SuppressWarnings("rawtypes")
    private static final Handle NOOP_HANDLE = new Handle() {
        @Override
        public void recycle(Object object) {
            // NOOP
        }
    };

 recycle的時候,什麼是都不做。

也就是,如果maxCapacityPerThread為0,我們就什麼物件都不快取。

一、獲取當前執行緒的Stack

就是這段程式碼:

        Stack<T> stack = threadLocal.get();

獲取當前執行緒的stack。 

threadLocal就是FastThreadLocal:

    private final FastThreadLocal<Stack<T>> threadLocal = new FastThreadLocal<Stack<T>>() {
        @Override
        protected Stack<T> initialValue() {
            return new Stack<T>(Recycler.this, Thread.currentThread(), maxCapacityPerThread, maxSharedCapacityFactor,
                    ratioMask, maxDelayedQueuesPerThread);
        }
    };

初始化的時候,會新建一個stack。 

二、從Stack裡面彈出物件

這個物件就是pop物件。

DefaultHandle<T> handle = stack.pop();

pop出來的物件是一個handle,物件就存在handle裡面,也就是要返回的就是handle.value。

然後我們分析pop的過程:

        @SuppressWarnings({ "unchecked", "rawtypes" })
        DefaultHandle<T> pop() {
            int size = this.size;
            if (size == 0) {
                if (!scavenge()) {
                    return null;
                }
                size = this.size;
            }
            size --;
            DefaultHandle ret = elements[size];
            elements[size] = null;
            if (ret.lastRecycledId != ret.recycleId) {
                throw new IllegalStateException("recycled multiple times");
            }
            ret.recycleId = 0;
            ret.lastRecycledId = 0;
            this.size = size;
            return ret;
        }

 首先有一個size,這個size就是這個stack裡面有多少個物件。如果size等於0,就會呼叫scavenge(),意思就是如果當前執行緒沒有物件了,但是我的物件有可能在別的執行緒那裡有物件,就去別的執行緒那裡找,後面再分析這個方法。

後續如果size不為0,那就從stack裡面取,size--。

DefaultHandle ret = elements[size]; elements[size] = null;就是把物件取出來並且設定原來的物件為null。

然後:

            ret.recycleId = 0;
            ret.lastRecycledId = 0;

這兩段程式碼的意思就是,物件被使用了,並沒有在回收次裡面。

三、建立物件並且繫結到Stack裡面

這一段原始碼就是我們這裡要分析的內容:

        if (handle == null) {
            handle = stack.newHandle();
            handle.value = newObject(handle);
        }

handle為空,就在stack裡面新建一個handle:


        DefaultHandle<T> newHandle() {
            return new DefaultHandle<T>(this);
        }

這個handle是DefaultHandle並且把this傳入進去,這個this就是stack:


        DefaultHandle(Stack<?> stack) {
            this.stack = stack;
        }

也就是每個handle都綁定了一個stack。

最後handle.value=newObject(handle)就是我們要的物件,這裡也不是很複雜。