Netty分布式高性能工具類recycler的使用及創(chuàng)建
前文傳送門:Netty分布式FastThreadLocal的set方法實現(xiàn)邏輯剖析
recycler的使用
這一小節(jié)開始學(xué)習(xí)recycler相關(guān)的知識, recycler是netty實現(xiàn)的一個輕量級對象回收站, 在netty中, recycler的使用也是相當(dāng)之頻繁的
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), 代表當(dāng)回收站沒有此類對象的時候, 可以通過這種方式創(chuàng)建對象
成員變量RECYCLER, 可以用來對此類對象的回收和再利用
定一個了一個靜態(tài)內(nèi)部類User, User中有個成員變量handle, 在構(gòu)造方法中為其賦值, handle的作用, 就是用于對象回收的
并且定義了一個方法recycle, 方法體中通過handle.recycle(this)這種方式將自身對象進(jìn)行回收, 通過這步操作, 就可以將對象回收到Recycler中
以上邏輯先做了解, 之后會進(jìn)行詳細(xì)分析
在main方法中, 通過RECYCLER的get方法獲取一個user, 然后進(jìn)行回收
再通過get方法將回收站的對象取出, 再次進(jìn)行回收, 最后判斷兩次取出的對象是否為一個對象, 最后結(jié)果輸出為true
以上demo就可以說明Recycler的回收再利用的功能
簡單介紹了demo, 我們就詳細(xì)的分析Recycler的機(jī)制
在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é)的學(xué)習(xí)中我們知道, 這里用于保存線程共享對象, 而這里的共享對象, 就是一個Stack類型的對象
每個stack中維護(hù)著一個DefaultHandle類型的數(shù)組, 用于盛放回收的對象, 有關(guān)stack和線程的關(guān)系如圖所示:

8-3-1
也就是說在每個Recycler中, 都維護(hù)著一個線程共享的棧, 用于對一類對象的回收
跟到Stack的構(gòu)造方法中
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;
}首先介紹幾個構(gòu)造方法中初始化的關(guān)鍵屬性:
屬性parent表示Reclycer對象自身
屬性thread表示當(dāng)前stack綁定的哪個線程
屬性maxCapacity表示當(dāng)前stack的最大容量, 表示stack最多能盛放多少個元素
屬性elements, 就表示stack中存儲的對象, 類型為DefaultHandle, 可以被外部對象引用, 從而實現(xiàn)回收
屬性ratioMask是用來控制對象回收的頻率的, 也就是說每次通過Reclycer回收對象的時候, 不是每次都會進(jìn)行回收, 而是通過該參數(shù)控制回收頻率
屬性maxDelayedQueues, 這里稍微有些復(fù)雜, 在很多時候, 一個線程創(chuàng)建的對象, 有可能會被另一個線程所釋放, 而另一個線程釋放的對象是不會放在當(dāng)前線程的stack中的, 而是會存放在一個叫做WeakOrderQueue的數(shù)據(jù)結(jié)構(gòu)中, 里面也是存放著一個個DefaultHandle, WeakOrderQueue會存放線程1創(chuàng)建的并且在線程2進(jìn)行釋放的對象
這里只是稍作了解, 之后的會對此做詳細(xì)剖析, 這里我們只需知道, maxDelayedQueues屬性的意思就是我這個線程能回收幾個其他創(chuàng)建的對象的線程, 假設(shè)當(dāng)前線程是線程1, maxDelayedQueues為2, 那么我線程1回收了線程2創(chuàng)建的對象, 又回收了線程3創(chuàng)建的對象, 那么不可能回收線程4創(chuàng)建的對象了, 因為maxDelayedQueues2, 我只能回收兩個線程創(chuàng)建的對象
屬性availableSharedCapacity, 表示在線程1中創(chuàng)建的對象, 在其他線程中緩存的最大個數(shù), 同樣, 相關(guān)邏輯會在之后的內(nèi)容進(jìn)行剖析
另外介紹兩個沒有在構(gòu)造方法初始化的屬性:
private WeakOrderQueue cursor, prev; private volatile WeakOrderQueue head;
這里相當(dāng)于指針, 用于指向WeakOrderQueue的, 這里也是稍作了解, 之后會進(jìn)行詳細(xì)剖析
有關(guān)stack異線程之間對象的關(guān)系如圖所示(簡略):

8-3-2
我們再繼續(xù)介紹Recycler的構(gòu)造方法, 同時熟悉有關(guān)stack各個參數(shù)的默認(rèn)值:
protected Recycler() {
this(DEFAULT_MAX_CAPACITY_PER_THREAD);
}這里調(diào)用了重載的構(gòu)造方法, 并傳入了參數(shù)DEFAULT_MAX_CAPACITY_PER_THREAD
DEFAULT_MAX_CAPACITY_PER_THREAD的默認(rèn)值是32768, 在static塊中被初始化的, 我們可以跟進(jìn)去自行分析
這個值就代表的每個線程中, stack中最多回收的元素的個數(shù)
繼續(xù)跟重載的構(gòu)造方法
protected Recycler(int maxCapacityPerThread) {
this(maxCapacityPerThread, MAX_SHARED_CAPACITY_FACTOR);
}這里又調(diào)用了重載的構(gòu)造方法, 并且傳入剛才傳入的32768和MAX_SHARED_CAPACITY_FACTOR
MAX_SHARED_CAPACITY_FACTOR默認(rèn)值是2, 同樣在static塊中進(jìn)行了初始化, 有關(guān)該屬性的用處稍后講解
繼續(xù)跟構(gòu)造方法:
protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor) {
this(maxCapacityPerThread, maxSharedCapacityFactor, RATIO, MAX_DELAYED_QUEUES_PER_THREAD);
}這里同樣調(diào)用了重載的構(gòu)造方法, 傳入了剛才32768和2, 還有兩個屬性RATIO和MAX_DELAYED_QUEUES_PER_THREAD
RATIO也在static中被初始化, 默認(rèn)值是8
同上, MAX_DELAYED_QUEUES_PER_THREAD的默認(rèn)值是2倍cpu核數(shù)
我們繼續(xù)跟構(gòu)造方法:
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);
}
}這里將幾個屬性進(jìn)行了初始化
首先看ratioMask, 這里的方法safeFindNextPositivePowerOfTwo的參數(shù)ratio為8, 該方法的意思就是大于等于8的2的冪次方-1, 這里就是ratioMask就是7
maxCapacityPerThread是剛才分析的32768, 是一個大于0的數(shù), 所以進(jìn)入else
maxCapacityPerThread為32768
maxSharedCapacityFactor的值為2
maxDelayedQueuesPerThread的值為2倍CPU核數(shù)
我們再回到Stack的構(gòu)造方法中
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默認(rèn)值為32768
ratioMask默認(rèn)值為7
maxDelayedQueues默認(rèn)值是兩倍cpu核數(shù)
availableSharedCapacity的默認(rèn)值是32768/2, 也就是16384
以上就是Recycler創(chuàng)建的相關(guān)邏輯,更多關(guān)于Netty分布式工具類recycler使用的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
SpringCloud中的Eureka注冊中心詳細(xì)解讀
這篇文章主要介紹了SpringCloud中的Eureka注冊中心詳細(xì)解讀,想要參與服務(wù)注冊發(fā)現(xiàn)的實例首先需要向Eureka服務(wù)器注冊信息,注冊在第一次心跳發(fā)生時提交,需要的朋友可以參考下2023-11-11
elasticsearch索引index之Mapping實現(xiàn)關(guān)系結(jié)構(gòu)示例
這篇文章主要介紹了elasticsearch索引index之Mapping實現(xiàn)關(guān)系結(jié)構(gòu)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-04-04
Spring3 整合MyBatis3 配置多數(shù)據(jù)源動態(tài)選擇SqlSessionFactory詳細(xì)教程
這篇文章主要介紹了Spring3 整合MyBatis3 配置多數(shù)據(jù)源動態(tài)選擇SqlSessionFactory詳細(xì)教程,需要的朋友可以參考下2017-04-04
Java8(291)之后禁用了TLS1.1使JDBC無法用SSL連接SqlServer2008的解決方法
這篇文章主要介紹了Java8(291)之后禁用了TLS1.1使JDBC無法用SSL連接SqlServer2008的解決方法,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-03-03
maven插件spring-boot-starter-tomcat的使用方式
這篇文章主要介紹了maven插件spring-boot-starter-tomcat的使用方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-07-07
SpringBoot中@Scheduled()注解以及cron表達(dá)式詳解
這篇文章主要介紹了SpringBoot中@Scheduled()注解以及cron表達(dá)式詳解,@Scheduled注解是Spring Boot提供的用于定時任務(wù)控制的注解,主要用于控制任務(wù)在某個指定時間執(zhí)行,或者每隔一段時間執(zhí)行,需要的朋友可以參考下2023-08-08
多線程Thread,Runnable,Callable實現(xiàn)方式
這篇文章主要為大家詳細(xì)介紹了Java多線程如何實現(xiàn)Thread,Runnable,Callable的方式,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-08-08
springboot(thymeleaf)中th:field和th:value的區(qū)別及說明
這篇文章主要介紹了springboot(thymeleaf)中th:field和th:value的區(qū)別及說明,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-10-10

