1. 程式人生 > >netty5.0原始碼解析 ByteBuf和相關輔助類

netty5.0原始碼解析 ByteBuf和相關輔助類

static final class Stack<T> implements Handle<T> {

        private static final int INITIAL_CAPACITY = 256;

        final Recycler<T> parent;
        final Thread thread;
        private T[] elements;//底層使用陣列實現儲存
        private int size;
        private final Map<T, Boolean> map = new IdentityHashMap<T, Boolean>(INITIAL_CAPACITY);

        @SuppressWarnings({ "unchecked", "SuspiciousArrayCast" })
        Stack(Recycler<T> parent, Thread thread) {
            this.parent = parent;
            this.thread = thread;
            elements = newArray(INITIAL_CAPACITY);
        }

        @Override
        public void recycle(T object) {
            parent.recycle(object, this);
        }

        T pop() {
            int size = this.size;
            if (size == 0) {
                return null;
            }
            size --;
            T ret = elements[size];
            elements[size] = null;
            map.remove(ret);
            this.size = size;
            return ret;
        }

        void push(T o) {
            if (map.put(o, Boolean.TRUE) != null) {
                throw new IllegalStateException("recycled already");
            }

            int size = this.size;
            if (size == elements.length) {
                T[] newElements = newArray(size << 1);
                System.arraycopy(elements, 0, newElements, 0, size);
                elements = newElements;
            }

            elements[size] = o;
            this.size = size + 1;
        }

        @SuppressWarnings({ "unchecked", "SuspiciousArrayCast" })
        private static <T> T[] newArray(int length) {
            return (T[]) new Object[length];
        }
    }

Recycler<T>中還定義了一個ThreadLocal<Stack<T>> threadLocal。ThreadLocal使得各執行緒能夠保持各自獨立的一個物件(每個執行緒對應一個例項)。通過ThreadLocal.set()將這個新建立的物件的引用儲存到各執行緒的自己的一個map中,每個執行緒都有這樣一個map,執行ThreadLocal.get()時,各執行緒從自己的map中取出放進去的物件或者呼叫initialValue()建立一個新物件,因此取出來的是各自執行緒中的物件,ThreadLocal例項是作為map的key來使用的。


ThreadLocal類介面很簡單,只有4個方法:
void set(T value)設定當前執行緒的執行緒區域性變數的值。
public T get()該方法返回當前執行緒所對應的執行緒區域性變數。
public void remove()將當前執行緒區域性變數的值刪除,目的是為了減少記憶體的佔用,該方法是JDK 5.0新增的方法。需要指出的是,當執行緒結束後,對應該執行緒的區域性變數將自動被垃圾回收,所以顯式呼叫該方法清除執行緒的區域性變數並不是必須的操作,但它可以加快記憶體回收的速度。
protected T initialValue()返回該執行緒區域性變數的初始值,該方法是一個protected的方法,顯然是為了讓子類覆蓋而設計的。這個方法是一個延遲呼叫方法,線上程第1次呼叫get()或set(T)時才執行,並且僅執行1次。ThreadLocal中的預設實現直接返回一個null。


關於ThreadLocal最後說一點,ThreadLocal不是用來解決物件共享訪問問題的,它僅僅只是讓各個執行緒都擁有了各自的物件。threadLocal本身僅僅只是作為一個key來幫助儲存目標物件,它跟目標物件沒有任何的聯絡僅僅只是些關於ThreadLocalMap操作方法。目標物件通過Thread中的ThreadLocalMap跟執行緒關聯。所以不需要考慮在threadLocal上面的同步問題,除非你線上程方法中去修改threadLocal自身的一些狀態,但這根本沒必要。所以將它設定為靜態變數就可以了免得每個執行緒都會有個threadLocal而浪費資源。多個執行緒共用一個threadLocal,但各個執行緒都擁有獨立的目標物件。