Netty原始碼分析第8章(高效能工具類FastThreadLocal和Recycler)---->第5節: 同線程回收物件
Netty原始碼分析第八章: 高效能工具類FastThreadLocal和Recycler
第五節: 同線程回收物件
上一小節剖析了從recycler中獲取一個物件, 這一小節分析在建立和回收是同線程的前提下, recycler是如何進行回收的
回顧第三小節的demo中的main方法:
public static void main(String[] args){
User user1 = RECYCLER.get();
user1.recycle();
User user2 = RECYCLER.get();
user2.recycle();
System.out.println(user1 ==user2);
}
這裡就是一個同線程回收物件的典型場景, 在一個執行緒中將物件建立並且回收, 我們的User物件定義了recycle方法
static class User{
private final Recycler.Handle<User> handle;
public User(Recycler.Handle<User> handle){
this.handle=handle;
}
public void recycle(){
handle.recycle(this);
}
}
這裡的recycle是通過handle物件的recycle方法實現物件回收的, 這裡實際呼叫的是DefaultHandle的recycle方法
我們跟進recycle方法:
public void recycle(Object object) {
if (object != value) {
throw new IllegalArgumentException("object does not belong to handle");
}
stack.push(this);
}
這裡如果回收的物件為null, 則丟擲異常
如果不為null, 則通過自身繫結stack的push方法將自身push到stack中
跟到push方法中:
void push(DefaultHandle<?> item) {
Thread currentThread = Thread.currentThread();
if (thread == currentThread) {
pushNow(item);
} else {
pushLater(item, currentThread);
}
}
這裡首先判斷當前執行緒, 和建立stack的時候儲存的執行緒是否是同一執行緒, 如果是, 說明是同線程回收物件, 則執行pushNow方法將物件放入stack中
跟到pushNow方法中:
private void pushNow(DefaultHandle<?> item) {
if ((item.recycleId | item.lastRecycledId) != 0) {
throw new IllegalStateException("recycled already");
}
item.recycleId = item.lastRecycledId = OWN_THREAD_ID;
int size = this.size;
if (size >= maxCapacity || dropHandle(item)) {
return;
}
if (size == elements.length) {
elements = Arrays.copyOf(elements, min(size << 1, maxCapacity));
}
elements[size] = item;
this.size = size + 1;
}
如果第一次回收, item.recycleId和item.lastRecycledId都為0, 所以不會進入if塊, 我們繼續往下看
item.recycleId = item.lastRecycledId = OWN_THREAD_ID 這一步將handle的recycleId和lastRecycledId賦值為OWN_THREAD_ID, OWN_THREAD_ID在每一個recycle中是唯一固定的, 這裡我們只需要記得這個概念就行
然後獲取當前size
如果size超過上限大小, 則直接返回
這裡還有個判斷dropHandle, 我們跟進去:
boolean dropHandle(DefaultHandle<?> handle) {
if (!handle.hasBeenRecycled) {
if ((++handleRecycleCount & ratioMask) != 0) {
return true;
}
handle.hasBeenRecycled = true;
}
return false;
}
if (!handle.hasBeenRecycled) 表示當前物件之前是否沒有被回收過, 如果是第一次回收, 這裡會返回true, 然後進入放到if
再看if中的判斷 if ((++handleRecycleCount & ratioMask) != 0)
handleRecycleCount表示當前位置stack回收了多少次物件(回收了多少次, 不代表回收了多少個物件, 因為不是每次回收都會被成功的儲存在stack), ratioMask我們之前分析過是7, 這裡 (++handleRecycleCount & ratioMask) != 0 表示回收的物件數如果不是8的倍數, 則返回true, 表示只回收1/8的物件
然後將hasBeenRecycled設定為true, 表示已經被回收
回到pushNow方法中:
如果size的大小等於stack中的陣列elements的大小, 則將陣列elements進行擴容
最後將size通過陣列下標的方式將當前handle設定到elements的元素中, 並將size進行自增
以上就是同線程回收物件的邏輯