Netty源碼分析第8章(高性能工具類FastThreadLocal和Recycler)---->第3節: recycler的使用和建立

 

Netty源碼分析第八章: 高性能工具類FastThreadLocal和Recyclerhtml

 

第三節: recycler的使用和建立數組

 

這一小節開始學習recycler相關的知識, recyclernetty實現的一個輕量級對象回收站, netty, recycler的使用也是至關之頻繁的緩存

recycler做用是保證了對象的循環利用, 對象使用完能夠經過recycler回收, 須要再次使用則從對象池中取出, 不用每次都建立新對象從而減小對系統資源的佔用, 同時也減輕了gc的壓力數據結構

 

這裏看一個示例:ide

public class RecyclerDemo { private static final Recycler<User> RECYCLER = new Recycler<User>() { @Override protected User newObject(Handle<User> handle) { return new User(handle); } }; static class User{ private final Recycler.Handle<User> handle; public User(Recycler.Handle<User> handle){ this.handle=handle; } public void recycle(){ handle.recycle(this); } } public static void main(String[] args){ User user1 = RECYCLER.get(); user1.recycle(); User user2 = RECYCLER.get(); user2.recycle(); System.out.println(user1==user2); } }

首先定義了一個Recycler的成員變量RECYCLER, 在匿名內部類中重寫了newObject方法, 也就是建立對象的方法, 該方法就是用戶自定義的工具

這裏newObject返回的new User(handle), 表明當回收站沒有此類對象的時候, 能夠經過這種方式建立對象源碼分析

 

成員變量RECYCLER, 能夠用來對此類對象的回收和再利用性能

 

定一個了一個靜態內部類User, User中有個成員變量handle, 在構造方法中爲其賦值, handle的做用, 就是用於對象回收的學習

而且定義了一個方法recycle, 方法體中經過handle.recycle(this)這種方式將自身對象進行回收, 經過這步操做, 就能夠將對象回收到Recyclerthis

以上邏輯先作了解, 以後會進行詳細分析

main方法中, 經過RECYCLERget方法獲取一個user, 而後進行回收

再經過get方法將回收站的對象取出, 再次進行回收, 最後判斷兩次取出的對象是否爲一個對象, 最後結果輸出爲true

以上demo就能夠說明Recycler的回收再利用的功能

 

簡單介紹了demo, 咱們就詳細的分析Recycler的機制

 

Recycler的類的源碼中, 咱們看到這一段邏輯:

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中維護着一個DefaultHandle類型的數組, 用於盛放回收的對象, 有關stack和線程的關係如圖所示:

 

8-3-1

也就是說在每一個Recycler, 都維護着一個線程共享的棧, 用於對一類對象的回收

 

跟到Stack的構造方法中:

Stack(Recycler<T> parent, Thread thread, int maxCapacity, int maxSharedCapacityFactor, int ratioMask, int maxDelayedQueues) { this.parent = parent; this.thread = thread; this.maxCapacity = maxCapacity; availableSharedCapacity = new AtomicInteger(max(maxCapacity / maxSharedCapacityFactor, LINK_CAPACITY)); elements = new DefaultHandle[min(INITIAL_CAPACITY, maxCapacity)]; this.ratioMask = ratioMask; this.maxDelayedQueues = maxDelayedQueues; }

首先介紹幾個構造方法中初始化的關鍵屬性:

屬性parent表示Reclycer對象自身

屬性thread表示當前stack綁定的哪一個線程

屬性maxCapacity表示當前stack的最大容量, 表示stack最多能盛放多少個元素

屬性elements, 就表示stack中存儲的對象, 類型爲DefaultHandle, 能夠被外部對象引用, 從而實現回收

屬性ratioMask是用來控制對象回收的頻率的, 也就是說每次經過Reclycer回收對象的時候, 不是每次都會進行回收, 而是經過該參數控制回收頻率

 

屬性maxDelayedQueues, 這裏稍微有些複雜, 在不少時候, 一個線程建立的對象, 有可能會被另外一個線程所釋放, 而另外一個線程釋放的對象是不會放在當前線程的stack中的, 而是會存放在一個叫作WeakOrderQueue的數據結構中, 裏面也是存放着一個個DefaultHandle, WeakOrderQueue會存放線程1建立的而且在線程2進行釋放的對象

這裏只是稍做了解, 以後的會對此作詳細剖析, 這裏咱們只需知道, maxDelayedQueues屬性的意思就是我這個線程能回收幾個其餘建立的對象的線程, 假設當前線程是線程1, maxDelayedQueues爲2, 那麼我線程1回收了線程2建立的對象, 又回收了線程3建立的對象, 那麼不可能回收線程4建立的對象了, 由於maxDelayedQueues2, 我只能回收兩個線程建立的對象

屬性availableSharedCapacity, 表示在線程1中建立的對象, 在其餘線程中緩存的最大個數, 一樣, 相關邏輯會在以後的內容進行剖析

另外介紹兩個沒有在構造方法初始化的屬性:

private WeakOrderQueue cursor, prev; private volatile WeakOrderQueue head;

這裏至關於指針, 用於指向WeakOrderQueue, 這裏也是稍做了解, 以後會進行詳細剖析

 

 

有關stack異線程之間對象的關係如圖所示(簡略):

8-3-2

咱們再繼續介紹Recycler的構造方法, 同時熟悉有關stack各個參數的默認值:

protected Recycler() { this(DEFAULT_MAX_CAPACITY_PER_THREAD); }

這裏調用了重載的構造方法, 並傳入了參數DEFAULT_MAX_CAPACITY_PER_THREAD

DEFAULT_MAX_CAPACITY_PER_THREAD的默認值是32768, static塊中被初始化的, 咱們能夠跟進去自行分析

這個值就表明的每一個線程中, stack中最多回收的元素的個數

 

繼續跟重載的構造方法:

protected Recycler(int maxCapacityPerThread) { this(maxCapacityPerThread, MAX_SHARED_CAPACITY_FACTOR); }

這裏又調用了重載的構造方法, 而且傳入剛纔傳入的32768MAX_SHARED_CAPACITY_FACTOR

MAX_SHARED_CAPACITY_FACTOR默認值是2, 一樣在static塊中進行了初始化, 有關該屬性的用處稍後講解

繼續跟構造方法:

protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor) { this(maxCapacityPerThread, maxSharedCapacityFactor, RATIO, MAX_DELAYED_QUEUES_PER_THREAD); }

這裏一樣調用了重載的構造方法, 傳入了剛纔327682, 還有兩個屬性RATIOMAX_DELAYED_QUEUES_PER_THREAD

RATIO也在static中被初始化, 默認值是8

同上, MAX_DELAYED_QUEUES_PER_THREAD的默認值是2cpu核數

 

咱們繼續跟構造方法:

protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor, int ratio, int maxDelayedQueuesPerThread) { ratioMask = safeFindNextPositivePowerOfTwo(ratio) - 1; if (maxCapacityPerThread <= 0) { this.maxCapacityPerThread = 0; this.maxSharedCapacityFactor = 1; this.maxDelayedQueuesPerThread = 0; } else { this.maxCapacityPerThread = maxCapacityPerThread; this.maxSharedCapacityFactor = max(1, maxSharedCapacityFactor); this.maxDelayedQueuesPerThread = max(0, maxDelayedQueuesPerThread); } }

這裏將幾個屬性進行了初始化

首先看ratioMask, 這裏的方法safeFindNextPositivePowerOfTwo的參數ratio8, 該方法的意思就是大於等於82的冪次方-1, 這裏就是ratioMask就是7

maxCapacityPerThread是剛纔分析的32768, 是一個大於0的數, 因此進入else

maxCapacityPerThread32768

maxSharedCapacityFactor的值爲2

 

maxDelayedQueuesPerThread的值爲2CPU核數

 

咱們再回到Stack的構造方法中:

Stack(Recycler<T> parent, Thread thread, int maxCapacity, int maxSharedCapacityFactor, int ratioMask, int maxDelayedQueues) { this.parent = parent; this.thread = thread; this.maxCapacity = maxCapacity; availableSharedCapacity = new AtomicInteger(max(maxCapacity / maxSharedCapacityFactor, LINK_CAPACITY)); elements = new DefaultHandle[min(INITIAL_CAPACITY, maxCapacity)]; this.ratioMask = ratioMask; this.maxDelayedQueues = maxDelayedQueues; }

根據Recycler初始化屬性的邏輯, 咱們能夠知道Stack中幾個屬性的值:

maxCapacity默認值爲32768

ratioMask默認值爲7

maxDelayedQueues默認值是兩倍cpu核數

availableSharedCapacity的默認值是32768/2, 也就是16384

 

以上就是Recycler建立的相關邏輯

 

上一節: FastThreadLocal的set方法

下一節: recycler中獲取對象

相關文章
相關標籤/搜索