Netty分布式高性能工具類recycler的使用及創(chuàng)建
前文傳送門:Netty分布式FastThreadLocal的set方法實現(xiàn)邏輯剖析
recycler的使用
這一小節(jié)開始學習recycler相關的知識, recycler是netty實現(xiàn)的一個輕量級對象回收站, 在netty中, recycler的使用也是相當之頻繁的
recycler作用是保證了對象的循環(huán)利用, 對象使用完可以通過recycler回收, 需要再次使用則從對象池中取出, 不用每次都創(chuàng)建新對象從而減少對系統(tǒng)資源的占用, 同時也減輕了gc的壓力
這里看一個示例
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, 在匿名內(nèi)部類中重寫了newObject方法, 也就是創(chuàng)建對象的方法, 該方法就是用戶自定義的
這里newObject返回的new User(handle), 代表當回收站沒有此類對象的時候, 可以通過這種方式創(chuàng)建對象
成員變量RECYCLER, 可以用來對此類對象的回收和再利用
定一個了一個靜態(tài)內(nèi)部類User, User中有個成員變量handle, 在構造方法中為其賦值, handle的作用, 就是用于對象回收的
并且定義了一個方法recycle, 方法體中通過handle.recycle(this)這種方式將自身對象進行回收, 通過這步操作, 就可以將對象回收到Recycler中
以上邏輯先做了解, 之后會進行詳細分析
在main方法中, 通過RECYCLER的get方法獲取一個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);
}
};這一段邏輯我們并不陌生, 在上一小節(jié)的學習中我們知道, 這里用于保存線程共享對象, 而這里的共享對象, 就是一個Stack類型的對象
每個stack中維護著一個DefaultHandle類型的數(shù)組, 用于盛放回收的對象, 有關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, 可以被外部對象引用, 從而實現(xiàn)回收
屬性ratioMask是用來控制對象回收的頻率的, 也就是說每次通過Reclycer回收對象的時候, 不是每次都會進行回收, 而是通過該參數(shù)控制回收頻率
屬性maxDelayedQueues, 這里稍微有些復雜, 在很多時候, 一個線程創(chuàng)建的對象, 有可能會被另一個線程所釋放, 而另一個線程釋放的對象是不會放在當前線程的stack中的, 而是會存放在一個叫做WeakOrderQueue的數(shù)據(jù)結構中, 里面也是存放著一個個DefaultHandle, WeakOrderQueue會存放線程1創(chuàng)建的并且在線程2進行釋放的對象
這里只是稍作了解, 之后的會對此做詳細剖析, 這里我們只需知道, maxDelayedQueues屬性的意思就是我這個線程能回收幾個其他創(chuàng)建的對象的線程, 假設當前線程是線程1, maxDelayedQueues為2, 那么我線程1回收了線程2創(chuàng)建的對象, 又回收了線程3創(chuàng)建的對象, 那么不可能回收線程4創(chuàng)建的對象了, 因為maxDelayedQueues2, 我只能回收兩個線程創(chuàng)建的對象
屬性availableSharedCapacity, 表示在線程1中創(chuàng)建的對象, 在其他線程中緩存的最大個數(shù), 同樣, 相關邏輯會在之后的內(nèi)容進行剖析
另外介紹兩個沒有在構造方法初始化的屬性:
private WeakOrderQueue cursor, prev; private volatile WeakOrderQueue head;
這里相當于指針, 用于指向WeakOrderQueue的, 這里也是稍作了解, 之后會進行詳細剖析
有關stack異線程之間對象的關系如圖所示(簡略):

8-3-2
我們再繼續(xù)介紹Recycler的構造方法, 同時熟悉有關stack各個參數(shù)的默認值:
protected Recycler() {
this(DEFAULT_MAX_CAPACITY_PER_THREAD);
}這里調(diào)用了重載的構造方法, 并傳入了參數(shù)DEFAULT_MAX_CAPACITY_PER_THREAD
DEFAULT_MAX_CAPACITY_PER_THREAD的默認值是32768, 在static塊中被初始化的, 我們可以跟進去自行分析
這個值就代表的每個線程中, stack中最多回收的元素的個數(shù)
繼續(xù)跟重載的構造方法
protected Recycler(int maxCapacityPerThread) {
this(maxCapacityPerThread, MAX_SHARED_CAPACITY_FACTOR);
}這里又調(diào)用了重載的構造方法, 并且傳入剛才傳入的32768和MAX_SHARED_CAPACITY_FACTOR
MAX_SHARED_CAPACITY_FACTOR默認值是2, 同樣在static塊中進行了初始化, 有關該屬性的用處稍后講解
繼續(xù)跟構造方法:
protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor) {
this(maxCapacityPerThread, maxSharedCapacityFactor, RATIO, MAX_DELAYED_QUEUES_PER_THREAD);
}這里同樣調(diào)用了重載的構造方法, 傳入了剛才32768和2, 還有兩個屬性RATIO和MAX_DELAYED_QUEUES_PER_THREAD
RATIO也在static中被初始化, 默認值是8
同上, MAX_DELAYED_QUEUES_PER_THREAD的默認值是2倍cpu核數(shù)
我們繼續(xù)跟構造方法:
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的參數(shù)ratio為8, 該方法的意思就是大于等于8的2的冪次方-1, 這里就是ratioMask就是7
maxCapacityPerThread是剛才分析的32768, 是一個大于0的數(shù), 所以進入else
maxCapacityPerThread為32768
maxSharedCapacityFactor的值為2
maxDelayedQueuesPerThread的值為2倍CPU核數(shù)
我們再回到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;
}根據(jù)Recycler初始化屬性的邏輯, 我們可以知道Stack中幾個屬性的值:
maxCapacity默認值為32768
ratioMask默認值為7
maxDelayedQueues默認值是兩倍cpu核數(shù)
availableSharedCapacity的默認值是32768/2, 也就是16384
以上就是Recycler創(chuàng)建的相關邏輯,更多關于Netty分布式工具類recycler使用的資料請關注腳本之家其它相關文章!
相關文章
spring cloud gateway集成hystrix全局斷路器操作
這篇文章主要介紹了spring cloud gateway集成hystrix全局斷路器操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
Springmvc請求參數(shù)類型轉(zhuǎn)換器及原生api代碼實例
這篇文章主要介紹了Springmvc請求參數(shù)類型轉(zhuǎn)換器及原生api代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-10-10
springboot實現(xiàn)定時器(一看即會,非常簡單)
這篇文章主要介紹了springboot實現(xiàn)定時器(一看即會,非常簡單),具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-12-12
SpringBoot實現(xiàn)定時發(fā)送郵件的三種方法案例詳解
這篇文章主要介紹了SpringBoot三種方法實現(xiàn)定時發(fā)送郵件的案例,Spring框架的定時任務調(diào)度功能支持配置和注解兩種方式Spring?Boot在Spring框架的基礎上實現(xiàn)了繼承,并對其中基于注解方式的定時任務實現(xiàn)了非常好的支持,本文給大家詳細講解,需要的朋友可以參考下2023-03-03

