Table of Contents
1. 接口
- io.netty.util.Recycler<T>
- 继承该类,并复写方法:protected abstract T newObject(Handle<T> handle);
- 获取对象:T get()
- 回收对象:boolean recycle(T o, Handle<T> handle)
需要注意的是,在回收时需要提供Handle对象,因此一般在实现newObject时,需要记录handle,比如T本身如果包含handle即可
- DefaultHandle实现了Handle接口,它有两个属性在初始化后不再变化
- object,表面被Pool的对象
- stack表面自己属于哪个Stack
| 代码: Recycler.java |
2. 特性
- 每个线程实际上有自己的线程池,且线程A申请的内存最终还是只有A能get,不会被其他线程get
- 理论上跨线程recycle会慢一点
- io.netty.recycler.maxCapacity属性能在对象在同一个线程申请和会收时起作用,当对象在线程A申请,在线程B释放时,不受io.netty.recycler.maxCapacity影响
3. 数据结构
Figure 1. Recycler & Thread
Figure 2. Stack & WeakOrderQueue
Stack
- Stack维护一个数组,用来指向被缓存的对象,在扩容时,需要拷贝整个数组,并有一个扩容上限maxCapacity
- 每个Recycler对象通过ThreadLocal为各个线程分配(首次引用时)独立的Stack
- 每个Stack有一个元素为WeakOrderQueue的单向链表,首次在非本线程释放对象时,会创建一个WeakOrderQueue对象
WeakOrderQueue
- 该对象用来存放在其他线程释放的对象,因此每个Stack在每个释放过的线程都有一个该对象。
- WeakOrderQueue是一个数组的单向链表,每个数组最多16个对象,这个单向链表在释放对象时往尾部插入,在请求对象时从头部取出
static FastThreadLocal<Map<Stack<?>, WeakOrderQueue>>
- 每个线程有一个Map<Stack, WeakOrderQueue>,该Map表面曾经在该线程recycle了哪些Stack的对象
- 在释放对象时,需要通过Stack查找到对应的WeakOrderQueue,然后把对象add到
4. 释放对象
- 在Recycle过程中,如果Hanlde.stack属性不等于当前线程的Stack,会查找上面的Map获得(或创建)WeakOrderQueue,然后向该WeakOrderQueue放置对象。如果创建了WeakOrderQueue,则会维护单向链表
- 在向WeakOrderQueue放置对象时,只会向最尾端的数组存放,如果该数组满了,就新申请一个
5. 获取对象(Recycler.get):
- 从本线程之前释放的对象中获取: 通过获得本线程的Stack,然后从该Stack中获取。
- 在Stack的数组为空时,会使用WeakOrderQueue,根据Stack.next获取WeakOrderQueue单向链表,然后从该单向链表中挪一部分对象过来。
5.1. 对象从WeakOrderQueue挪动到Stack
- 从单向链表中获取head的WeakOrderQueue,然后数组列表中最多一个节点(16个对象)的对象移动到Stack
- 如果上一步成功则返回,否则继续操作下一个WeakOrderQueue
- 为了保持无锁,WeakOrderQueue的数组列表的每个节点(16个对象)维护一个写位置指针和读位置指针,写位置指针使用AtomicInteger,读位置指针使用普通的int。
- 写位置指针不使用getAndIncrease或set,而是使用lazySet。根据下面的文章lazySet使用StoreStore Barrier在单writer时非常有用,比volatile性能好很多。
6. 同步
- 在整个过程中,有一个地方需要同步:创建并将WeakOrderQueue添加到单向链表中
WeakOrderQueue(Stack<?> stack, Thread thread) {
head = tail = new Link();
owner = new WeakReference<Thread>(thread);
synchronized (stack) {
next = stack.head;
stack.head = this;
}
}
- Stack.next需要是volitile,因为他被其他线程更改以维护单向链表
private volatile WeakOrderQueue head;
- 将WeakOrderQueue从单向链表删除不需要同步,因为挪动WeakOrderQueue中的对象到Stack这个操作,只会在Stack所在的线程会做

0 评论:
Post a Comment