Recycler对象池分析
1. 示例代码与运行结果
以下是一个使用 Netty Recycler 对象池的测试示例,展示了对象的获取、使用、回收及复用的过程。
public class RecyclerTest {
static class WrapRecycler {
private boolean tmp;
private final static Recycler<WrapRecycler> RECYCLER = new Recycler<WrapRecycler>() {
@Override
protected WrapRecycler newObject(Handle<WrapRecycler> handle) {
return new WrapRecycler(handle);
}
};
Recycler.Handle<WrapRecycler> handle;
WrapRecycler(Recycler.Handle<WrapRecycler> handle) {
this.handle = handle;
this.tmp = false;
}
static WrapRecycler getInstance() {
return RECYCLER.get();
}
void recycle() {
this.tmp = false;
handle.recycle(this);
}
public boolean getTmp() {
return tmp;
}
public void setTmp(boolean tmp) {
this.tmp = tmp;
}
}
public static void main(String[] args) {
WrapRecycler instance = WrapRecycler.getInstance();
System.out.println(instance.hashCode());
System.out.println(instance.getTmp());
instance.setTmp(true);
System.out.println(instance.getTmp());
instance.recycle();
instance = WrapRecycler.getInstance();
System.out.println(instance.hashCode());
System.out.println(instance.getTmp());
}
}运行结果如下,两次获取的对象哈希值(hashCode)相同,且第二次获取时 tmp 状态被重置,说明是同一个对象被复用。
41359092
false
true
41359092
false2. Recycler 类结构分析
2.1 整体架构
- 抽象类设计:
Recycler是一个抽象类。在目标类中创建对象池实例时,需要实现newObject(Handle handle)方法,用于创建特定类的实例。 - 存储机制:
Recycler对象池内部通过对象数组维护池中的对象实例,对外提供统一的对象创建和回收接口。 核心方法:
Recycler#get:获取对象池中对象的入口。如果有可用对象则直接返回,否则调用newObject()方法创建新对象。Recycler#recycle:对象使用完毕后回收对象。注意:该方法只能回收当前线程创建的对象,且现已标记为@Deprecated,不建议使用。建议使用Recycler.Handle#recycle方法,它可以回收非当前线程创建的对象,复用性和性能更好。
- 核心组件:
Recycler对象池的实现主要依赖三个核心组件:Handle、WeakOrderQueue和Stack。
2.2 Handle 组件
Handle 组件主要用来对外提供一个 recycle() 对象回收接口。每个池化对象在 newObject() 创建时都会绑定一个 Handle,用作该对象的回收凭证。
static final class DefaultHandle<T> implements Handle<T> {
private int lastRecycledId;
private int recycleId;
boolean hasBeenRecycled;
private Stack<?> stack;
private Object value;
DefaultHandle(Stack<?> stack) {
this.stack = stack;
}
@Override
public void recycle(Object object) {
if (object != value) {
throw new IllegalArgumentException("object does not belong to handle");
}
stack.push(this);
}
}- 对象绑定:每个
Handle关联一个value字段,用于存放具体的池化对象。在对象池中,所有的池化对象都被这个Handle包装,Handle是对象池管理的基本单位,Stack中存储管理的也是Handle类。 - 获取逻辑:调用
get()方法从对象池中获取复用对象。如果对象池为空,则在Stack中创建新的Handle实例,并通过newObject()方法创建对象赋给handle.value属性。
public final T get() {
if (maxCapacityPerThread == 0) {
return newObject((Handle<T>) NOOP_HANDLE);
}
Stack<T> stack = threadLocal.get();
DefaultHandle<T> handle = stack.pop();
if (handle == null) {
handle = stack.newHandle();
handle.value = newObject(handle);
}
return (T) handle.value;
}2.3 Stack 组件
Stack 组件通过 FastThreadLocal 类为每个线程维护一个与线程绑定的栈,用来存储复用的对象。
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);
}
};- 线程绑定:线程在通过
Recycler的get()方法获取复用对象时,首先获取与当前线程绑定的Stack,再从Stack中pop出Handle包装实例。
public final T get() {
if (maxCapacityPerThread == 0) {
return newObject((Handle<T>) NOOP_HANDLE);
}
Stack<T> stack = threadLocal.get();
DefaultHandle<T> handle = stack.pop();
if (handle == null) {
handle = stack.newHandle();
handle.value = newObject(handle);
}
return (T) handle.value;
}2.4 WeakOrderQueue 组件
WeakOrderQueue 是 Recycler 的一个内部私有类,用来暂存待回收的对象。Handle.recycle() 可以回收不是当前线程创建的对象,主要依靠 WeakOrderQueue 实现。
private static final FastThreadLocal<Map<Stack<?>, WeakOrderQueue>> DELAYED_RECYCLED =
new FastThreadLocal<Map<Stack<?>, WeakOrderQueue>>() {
@Override
protected Map<Stack<?>, WeakOrderQueue> initialValue() {
return new WeakHashMap<Stack<?>, WeakOrderQueue>();
}
};- 回收逻辑:如果是当前线程创建的对象,直接就把对象放到当前线程对应的
Stack中;如果不是,则放入WeakOrderQueue中。每个线程维护着一个WeakHashMap。
public void recycle(Object object) {
if (object != value) {
throw new IllegalArgumentException("object does not belong to handle");
}
stack.push(this);
}void push(DefaultHandle<?> item) {
Thread currentThread = Thread.currentThread();
if (thread == currentThread) {
pushNow(item);
} else {
pushLater(item, currentThread);
}
}private void pushLater(DefaultHandle<?> item, Thread thread) {
Map<Stack<?>, WeakOrderQueue> delayedRecycled = DELAYED_RECYCLED.get();
WeakOrderQueue queue = delayedRecycled.get(this);
if (queue == null) {
if (delayedRecycled.size() >= maxDelayedQueues) {
delayedRecycled.put(this, WeakOrderQueue.DUMMY);
return;
}
if ((queue = WeakOrderQueue.allocate(this, thread)) == null) {
return;
}
delayedRecycled.put(this, queue);
} else if (queue == WeakOrderQueue.DUMMY) {
return;
}
queue.add(item);
}- 对象 scavenging:在从
Stack获取对象池时,如果Stack中可用对象为空,会尝试遍历多线程对应的WeakOrderQueue链表中回收恢复对象。
public final T get() {
if (maxCapacityPerThread == 0) {
return newObject((Handle<T>) NOOP_HANDLE);
}
Stack<T> stack = threadLocal.get();
DefaultHandle<T> handle = stack.pop();
if (handle == null) {
handle = stack.newHandle();
handle.value = newObject(handle);
}
return (T) handle.value;
}DefaultHandle<T> pop() {
int size = this.size;
if (size == 0) {
if (!scavenge()) {
return null;
}
size = this.size;
}
size--;
DefaultHandle ret = elements[size];
elements[size] = null;
if (ret.lastRecycledId != ret.recycleId) {
throw new IllegalStateException("recycled multiple times");
}
ret.recycleId = 0;
ret.lastRecycledId = 0;
this.size = size;
return ret;
}boolean scavengeSome() {
WeakOrderQueue prev;
WeakOrderQueue cursor = this.cursor;
if (cursor == null) {
prev = null;
cursor = head;
if (cursor == null) {
return false;
}
} else {
prev = this.prev;
}
boolean success = false;
do {
if (cursor.transfer(this)) {
success = true;
break;
}
WeakOrderQueue next = cursor.next;
if (cursor.owner.get() == null) {
if (cursor.hasFinalData()) {
for (;;) {
if (cursor.transfer(this)) {
success = true;
} else {
break;
}
}
}
if (prev != null) {
prev.setNext(next);
}
} else {
prev = cursor;
}
cursor = next;
} while (cursor != null && !success);
this.prev = prev;
this.cursor = cursor;
return success;
}
3. 总结
- Netty 实现的轻量级对象池实现了对象的复用和回收,核心组件包括
Stack、WeakOrderQueue和Handle。 Stack相当于 MyBatis 的一级缓存,与线程绑定。线程内对象的获取和回收都使用绑定的Stack;复用对象时直接从Stack中申请,使用完后如果对象是自己创建的则放入Stack。- 在对象回收时,如果对象不是当前线程创建的,则不能放入
Stack中回收,而是放入WeakOrderQueue中。所有的Queue组成一个链表作为对象回收的仓库,当Stack中无可用的对象时会遍历链表回收对象,实现了多线程之间对象回收的共享。

说明
本文基于 Netty 早期版本(约 4.1.x 时期)的 Recycler 实现进行分析。Netty 后续版本中对象池内部实现(如 Stack 与 Pool 结构)可能有所演进,具体细节请以实际使用的 Netty 版本源码为准。
版权声明:本文为原创文章,版权归 戴老师的博客 所有,转载请联系博主获得授权。
本文地址:https://1diff.fun/archives/recycler-dui-xiang-chi-fen-xi.html
如果对本文有什么问题或疑问都可以在评论区留言,我看到后会尽量解答。