Netty 轻量级对象池Recycler分析
Recycler对象池在Netty中使用广泛,主要用来完成对象的管理,如获取对象、对象用完之后回收对象,这样下次再获取该类型对象时可以直接从对象池中获取,减少对象的创建性能消耗。如PooledUnsafeDirectByteBuf中对象池的使用:
private static final Recycler<PooledUnsafeDirectByteBuf> RECYCLER = new Recycler<PooledUnsafeDirectByteBuf>() {
@Override
protected PooledUnsafeDirectByteBuf newObject(Handle<PooledUnsafeDirectByteBuf> handle) {
return new PooledUnsafeDirectByteBuf(handle, 0);
}
};
static PooledUnsafeDirectByteBuf newInstance(int maxCapacity) {
PooledUnsafeDirectByteBuf buf = RECYCLER.get();
buf.reuse(maxCapacity);
return buf;
}
使用对象池有如下的好处:
- 对象复用——因为对象都缓存在对象池中,因此对象得以复用,不用每次都创建对象,减少new的性能消耗;
- 减少young GC——因为减少了不必要的对象创建,因此JVM年轻代垃圾减少,因此young GC减少。
下面详细分析轻量级对象池Recycler的原理。
一、Recycler的使用
public class RecyclerTest {
private static final Recycler<User> RECYCLER = new Recycler<User>() {
@Override
protected User newObject(Handle<User> handle) {
return new User(handle);
}
};
public static class User {
private 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) throws InterruptedException {
User user = RECYCLER.get();
user.recycle(); // 同线程回收对象
// new FastThreadLocalThread(() -> {
// user.recycle();
// }).start(); // 异线程回收对象
System.out.println(user == RECYCLER.get()); // true
}
}
如上是Recycler使用的一个例子,通过RECYCLER.get()
获取User对象,对象用完之后调用user.recycle()
回收对象。回收对象有两种方式,一种是同线程回收对象,即对象在一个线程中分配,同时在该线程中回收对象;另一种是异线程回收对象,即对象在一个线程中分配,但在另一个线程中回收对象。
二、Recycler的创建
从上面的例子可以看到,创建Recycler对象池时需要实现newObject()抽象方法。下面看其构造器:
private final int maxCapacityPerThread; // 32768
private final int maxSharedCapacityFactor; // 2
private final int ratioMask; // 7
private final int maxDelayedQueuesPerThread; // 2倍的CPU核数
protected Recycler() {
this(DEFAULT_MAX_CAPACITY_PER_THREAD);
}
protected Recycler(int maxCapacityPerThread) {
this(maxCapacityPerThread, MAX_SHARED_CAPACITY_FACTOR);
}
protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor) {
this(maxCapacityPerThread, maxSharedCapacityFactor, RATIO, MAX_DELAYED_QUEUES_PER_THREAD);
}
protected Recycler(int maxCapacityPerThread, int maxSharedCapacityFactor,
int ratio, int maxDelayedQueuesPerThread) {
ratioMask = safeFindNextPositivePowerOfTwo(ratio) - 1; // 7
if (maxCapacityPerThread <= 0) {
this.maxCapacityPerThread = 0;
this.maxSharedCapacityFactor = 1;
this.maxDelayedQueuesPerThread = 0;
} else {
this.maxCapacityPerThread = maxCapacityPerThread; // 32768
this.maxSharedCapacityFactor = max(1, maxSharedCapacityFactor); // 2
this.maxDelayedQueuesPerThread = max(0, maxDelayedQueuesPerThread); // 2倍CPU核数
}
}
在默认情况下,Recycler实例的maxCapacityPerThread变量为32768,maxSharedCapacityFactor为2,ratioMask为7,maxDelayedQueuesPerThread为2倍的CPU核数。同时可以看到Recycler实例包含的FastThreadLocal threadLocal变量:
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);
}
};
由于threadLocal变量是FastThreadLocal类型,因此不同线程访问threadLocal时,将获得线程本地变量Stack实例,因此线程和Stack实例是一一对应的。下面看Stack的结构:
// Stack成员变量和构造器
final Recycler<T> parent;
final Thread thread;
final AtomicInteger availableSharedCapacity; // 16384
final int maxDelayedQueues; // WeakOrderQueue最大个数
private final int maxCapacity; // elements数组最大大小
private final int ratioMask; // 控制对象的回收比率
private DefaultHandle<?>[] elements;
private int size; // Stack缓存的DefaultHandle对象个数
private int handleRecycleCount = -1; // Start with -1 so the first one will be recycled.
private WeakOrderQueue cursor, prev;
private volatile WeakOrderQueue head;
Stack(Recycler<T> parent, Thread thread, int maxCapacity, int maxSharedCapacityFactor,
int ratioMask, int maxDelayedQueues) {
this.parent = parent; // Recycler
this.thread = thread; // Reactor线程,创建该Stack的线程
this.maxCapacity = maxCapacity; // 32768
// maxSharedCapacityFactor: 2, availableSharedCapacity: 16384
availableSharedCapacity = new AtomicInteger(max(maxCapacity / maxSharedCapacityFactor, LINK_CAPACITY));
elements = new DefaultHandle[min(INITIAL_CAPACITY, maxCapacity)]; // 256
this.ratioMask = ratioMask; // 7
this.maxDelayedQueues = maxDelayedQueues; // 2*CPU核数
}
从上图可以看到,Stack中包含一个elements数组,该数组用来保存DefaultHandle实例,而DefaultHandle实例中保存了实际回收的对象,如User。thread表示实际创建该Stack的线程,即Stack所属线程(如Thread1)。ratioMask用来控制对象回收的比率,默认只回收1/8的对象。maxCapacity表示elements数组的最大大小。maxDelayedQueues表示在异线程回收对象时,由其他线程(如Thread2)回收对象时创建的WeakOrderQueue最大个数,默认为2倍CPU核数。availableSharedCapacity表示异线程回收对象时,其他线程能保存的被回收对象的最大个数。指针head、prev、cursor指向异线程回收对象的情况下,由其他线程(如Thread2)回收对象时创建的WeakOrderQueue串联起来的链表。
三、从Recycler获取对象
1.获取当前线程的Stack
从上面的例子可以看到,对象是通过Recycler.get()
获取的:
public final T get() {
if (maxCapacityPerThread == 0) {
return newObject((Handle<T>) NOOP_HANDLE); // 对象用完不会回收
}
Stack<T> stack = threadLocal.get();
DefaultHandle<T> handle = stack.pop(); // 从缓存中弹出一个DefaultHandle对象
if (handle == null) {
handle = stack.newHandle();
handle.value = newObject(handle); // 创建的对象,保存到DefaultHandle
}
return (T) handle.value; // T类型的对象
}
如果maxCapacityPerThread为0,则直接通过newObject()创建对象,且对象使用完之后并不会缓存到对象池中。如果maxCapacityPerThread大于0,则线程通过threadLocal获取Stack实例,上面已经分析过threadLocal的作用和Stack的初始化过程,这里不再详述。
2.从Stack弹出对象
得到Stack之后,调用stack.pop()
获取缓存的DefaultHandle实例,即从Stack弹出DefaultHandle对象。
DefaultHandle<T> pop() {
int size = this.size;
if (size == 0) {
if (!scavenge()) { // 从其他线程的WeakOrderQueue回收DefaultHandle
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;
}
pop()方法中如果size不为0,即elements数组中存在缓存的DefaultHandle实例,则直接通过数组索引的方式获取DefaultHandle实例,并更新size大小。如果size为0,则需要先通过scavenge()方法,从其他线程的WeakOrderQueue中回收DefaultHandle对象。这些WeakOrderQueue都是其他线程在异线程回收对象时创建的,用来暂时保存由Stack对应线程创建的DefaultHandle对象。scavenge()方法将在回收对象到Recycler中的异线程收割对象部分再详细分析。
假设stack.pop()
获取到了一个DefaultHandle实例,则直接拿出其中的实际对象并返回。如果未获取到DefaultHandle实例,则创建一个DefaultHandle对象并绑定Stack。
3.创建DefaultHandle对象并绑定Stack
DefaultHandle<T> handle = stack.pop(); // 从缓存中弹出一个DefaultHandle对象
if (handle == null) {
handle = stack.newHandle();
handle.value = newObject(handle); // 创建的对象,保存到DefaultHandle
}
首先调用stack.newHandle()
创建DefaultHandle实例:
DefaultHandle<T> newHandle() { // 创建DefaultHandle,与Stack绑定
return new DefaultHandle<T>(this);
}
static final class DefaultHandle<T> implements Handle<T> {
private int lastRecycledId;
private int recycleId;
boolean hasBeenRecycled; // 是否已经被回收过
private Stack<?> 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); // 对象回收时将对应的DefaultHandle放入Stack中
}
}
DefaultHandle创建过程中将会绑定当前的Stack实例。然后调用newObject(handle)创建实例的对象,例如User,并将引用保存到DefaultHandle的value变量中。至此,DefaultHandle创建完毕。最后将DefaultHandle中保存的对象引用返回。
四、回收对象到Recycler
从前面的例子可以看到,回收对象通过以下方式完成:
user.recycle();
public static class User {
private Recycler.Handle<User> handle;
public User(Recycler.Handle<User> handle) {
this.handle = handle;
}
public void recycle() {
handle.recycle(this);
}
}
最终回收对象时,调用的是Handle.recycle(User)方法。
// DefaultHandle
public void recycle(Object object) {
if (object != value) {
throw new IllegalArgumentException("object does not belong to handle");
}
stack.push(this); // 对象回收时将对应的DefaultHandle放入Stack中
}
这里调用Stack.push(DefaultHandle)回收对象:
void push(DefaultHandle<?> item) {
Thread currentThread = Thread.currentThread();
if (thread == currentThread) { // 同线程回收对象
pushNow(item);
} else { // 异线程回收对象
pushLater(item, currentThread);
}
}
从该push()方法也可以看出,回收对象有两种情况。如果对象是在获取对象的线程中进行回收,则直接调用pushNow()方法回收对象;如果对象不是在获取对象的线程中进行回收,则调用pushLater()方法进行回收。下面分别进行讨论。
1.同线程回收对象
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)) {
// Hit the maximum capacity or should drop - drop the possibly youngest object.
return;
}
if (size == elements.length) { // 扩容
elements = Arrays.copyOf(elements, min(size << 1, maxCapacity));
}
elements[size] = item;
this.size = size + 1;
}
同线程回收对象时,首先判断Stack中缓存的DefaultHandle个数是否已达到maxCapacity,即32768。如果已达到,直接丢弃当前回收的DefaultHandle。之后通过dropHandle()方法判断是否应该丢弃本次回收的DefaultHandle实例:
boolean dropHandle(DefaultHandle<?> handle) { // 判断是否回收handle对象
if (!handle.hasBeenRecycled) {
if ((++handleRecycleCount & ratioMask) != 0) { // 默认只回收1/8的对象
// Drop the object.
return true;
}
handle.hasBeenRecycled = true;
}
return false;
}
dropHandle()通过handleRecycleCount变量控制是否丢弃本次回收的DefaultHandle实例,可以看到默认情况下,只回收1/8的对象。并且当某对象判断为可以回收之后,会将hasBeenRecycled置为true。这样后面该对象再次被回收时,会被直接判断为回收。
假设判断当前Stack缓存的DefaultHandle个数之后,未超过maxCapacity,且dropHandle(item)
返回false,即不丢弃本次回收的DefaultHandle对象,则将本次回收的DefaultHandle放入elements数组中。放入之前如果需要扩容,则进行扩容。
2.异线程回收对象
// 延迟回收的队列
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>();
}
};
private void pushLater(DefaultHandle<?> item, Thread thread) {
Map<Stack<?>, WeakOrderQueue> delayedRecycled = DELAYED_RECYCLED.get();
WeakOrderQueue queue = delayedRecycled.get(this);
if (queue == null) {
// 达到最大WeakOrderQueue个数,则放弃对象回收
if (delayedRecycled.size() >= maxDelayedQueues) {
delayedRecycled.put(this, WeakOrderQueue.DUMMY);
return;
}
if ((queue = WeakOrderQueue.allocate(this, thread)) == null) { // 创建WeakOrderQueue
// drop object
return;
}
delayedRecycled.put(this, queue); // 创建的WeakOrderQueue保存到Map
} else if (queue == WeakOrderQueue.DUMMY) {
// drop object
return;
}
queue.add(item); // DefaultHandle保存到WeakOrderQueue
}
异线程回收对象的过程由pushLater()方法实现,该过程分为3步:获取weakOrderQueue、创建weakOrderQueue和将对象保存到WeakOrderQueue。
获取WeakOrderQueue
首先通过FastThreadLocal变量DELAYED_RECYCLED获取Map<Stack<?>, WeakOrderQueue> delayedRecycled
,可以看到某线程在回收其他线程获取的对象时使用了Map<Stack<?>, WeakOrderQueue>
数据结构。这个Map中的key是Stack,即创建Stack、获取对象的线程对应的Stack,value为异线程回收对象时,回收由其他线程获取的对象时创建的WeakOrderQueue。由于对某个线程来说,这个异线程回收的对象不只是一个Stack、一个线程获取的对象,因此这里用Map数据结构,分别用于回收保存不同线程获取的不同的对象。
然后以当前Stack为key,得到与该Stack关联的WeakOrderQueue。
Map<Stack<?>, WeakOrderQueue> delayedRecycled = DELAYED_RECYCLED.get();
WeakOrderQueue queue = delayedRecycled.get(this);
创建WeakOrderQueue
如果获取到的WeakOrderQueue为null,即表示之前未回收过该Stack的DefaultHandle对象,则先创建WeakOrderQueue实例。
if (delayedRecycled.size() >= maxDelayedQueues) { // 达到最大WeakOrderQueue个数,则放弃对象回收
// Add a dummy queue so we know we should drop the object
delayedRecycled.put(this, WeakOrderQueue.DUMMY);
return;
}
创建WeakOrderQueue之前先判断上述的Map容量是否已达到最大值maxDelayedQueues,如果达到最大值,则直接保存一个WeakOrderQueue.DUMMY value。以后只要是该Stack的DefaultHandle对象在该线程回收时直接丢弃掉。
else if (queue == WeakOrderQueue.DUMMY) {
// drop object
return;
}
如果Map容量未达到最大值maxDelayedQueues,则创建WeakOrderQueue并保存到delayedRecycled中:
if ((queue = WeakOrderQueue.allocate(this, thread)) == null) { // 创建WeakOrderQueue
// drop object
return;
}
delayedRecycled.put(this, queue); // 创建的WeakOrderQueue保存到Map
static WeakOrderQueue allocate(Stack<?> stack, Thread thread) {
// We allocated a Link so reserve the space
// 创建WeakOrderQueue的时候判断是否还能分配LINK_CAPACITY空间,如果不能,直接返回null
return reserveSpace(stack.availableSharedCapacity, LINK_CAPACITY)
? new WeakOrderQueue(stack, thread) : null;
}
调用WeakOrderQueue.allocate()方法创建WeakOrderQueue时,先判断是否还能分配LINK_CAPACITY空间:
private static boolean reserveSpace(AtomicInteger availableSharedCapacity, int space) {
assert space >= 0;
for (;;) {
int available = availableSharedCapacity.get();
if (available < space) { // 可用空间不够
return false;
}
if (availableSharedCapacity.compareAndSet(available, available - space)) { // CAS
return true;
}
}
}
如果可以分配的空间余量availableSharedCapacity小于LINK_CAPACITY(16),则直接返回null,则本次回收的DefaultHandle直接丢弃。如果可以分配空间,则通过WeakOrderQueue构造器创建对象:
private WeakOrderQueue(Stack<?> stack, Thread thread) {
head = tail = new Link(); // 分配一个Link
owner = new WeakReference<Thread>(thread);
synchronized (stack) { // 头插法插入Stack的WeakOrderQueue列表
next = stack.head;
stack.head = this;
}
availableSharedCapacity = stack.availableSharedCapacity;
}
WeakOrderQueue是由一个个的Link对象链接而成的,WeakOrderQueue初始化时会创建一个Link对象:
private static final class Link extends AtomicInteger {
private final DefaultHandle<?>[] elements = new DefaultHandle[LINK_CAPACITY]; // 16
private int readIndex; // 异线程回收时用
private Link next; // 指向下一个Link对象
}
Link对象默认可以保存LINK_CAPACITY(16)个DefaultHandle实例。在创建WeakOrderQueue的过程中,同时需要将该WeakOrderQueue与Stack绑定。
synchronized (stack) { // 头插法插入Stack的WeakOrderQueue列表
next = stack.head;
stack.head = this;
}
可以看到,Stack通过head指针与异线程的WeakOrderQueue进行绑定。head指向的是一个WeakOrderQueue的链表。这些链表中的WeakOrderQueue,是不同异线程在回收Stack对应线程获取的对象时,用于保存这些对象创建的。这样子的一个链表,便于后续Stack从异线程的WeakOrderQueue收割对象,即DefaultHandle。
在获取到或创建WeakOrderQueue之后,就将本次异线程回收的DefaultHandle保存到该queue中。
将对象保存到WeakOrderQueue
queue.add(item); // DefaultHandle保存到WeakOrderQueue
void add(DefaultHandle<?> handle) { // handle暂时存放到WeakOrderQueue
handle.lastRecycledId = id;
Link tail = this.tail; // 添加到尾部Link
int writeIndex;
if ((writeIndex = tail.get()) == LINK_CAPACITY) { // 尾部Link已经没有空间可以存放handle了
// 无空间可以分配了,直接丢弃handle
if (!reserveSpace(availableSharedCapacity, LINK_CAPACITY)) {
// Drop it.
return;
}
// We allocate a Link so reserve the space
this.tail = tail = tail.next = new Link(); // 尾部新增Link
writeIndex = tail.get();
}
tail.elements[writeIndex] = handle;
handle.stack = null; // 回收完毕,stack置为null
tail.lazySet(writeIndex + 1); // 增加元素计数
}
保存对象是直接在WeakOrderQueue尾部Link插入的。保存时,先判断tail Link对象是否已经没有空间可以存放handle了,如果tail Link已满,则先判断是否还有空间可以分配Link对象:
if (!reserveSpace(availableSharedCapacity, LINK_CAPACITY)) { // 无空间可以分配了,直接丢弃handle
// Drop it.
return;
}
如果没有空间可以分配Link了,直接丢弃本次回收的对象。否则,创建一个Link对象并追加到tail。
如果tail Link有空间或者新分配了一个Link对象,那么保存回收的DefaultHandle对象。
tail.elements[writeIndex] = handle;
handle.stack = null; // 回收完毕,stack置为null
tail.lazySet(writeIndex + 1); // 增加元素计数
至此,异线程回收对象的过程分析完毕。
3.异线程收割对象
在分析对象获取的时候,可以知道当Stack没有缓存的DefaultHandle时,会调用scavenge()
方法,从其他线程的WeakOrderQueue回收DefaultHandle。下面就来分析该异线程收割对象的过程。
DefaultHandle<T> pop() { // 获取对象
int size = this.size;
if (size == 0) {
if (!scavenge()) { // 从其他线程的WeakOrderQueue回收DefaultHandle
return null;
}
size = this.size;
}
// ...
}
// 从其他线程的WeakOrderQueue转移handle(异线程收割对象)
boolean scavenge() {
// continue an existing scavenge, if any
if (scavengeSome()) {
return true;
}
// reset our scavenge cursor 重置指针
prev = null;
cursor = head;
return false;
}
可以知道,在调用scavenge()方法时,其最终调用到了scavengeSome()方法从其他线程的WeakOrderQueue中转移DefaultHandle对象。
boolean scavengeSome() {
WeakOrderQueue cursor = this.cursor;
if (cursor == null) {
cursor = head;
if (cursor == null) {
return false;
}
}
boolean success = false; // 是否成功从其他线程的WeakOrderQueue回收到对象
WeakOrderQueue prev = this.prev;
do {
// 从cursor指向的WeakOrderQueue收割对象到当前Stack,每次transfer,只从一个Link回收对象
if (cursor.transfer(this)) {
success = true;
break;
}
WeakOrderQueue next = cursor.next;
if (cursor.owner.get() == null) { // 弱引用,表示owner线程已经GC
if (cursor.hasFinalData()) {
for (;;) { // 不断transfer Link对象
if (cursor.transfer(this)) { // 每次传输一个Link的handle对象到当前Stack
success = true;
} else { // 返回false,表示传输完毕
break;
}
}
}
if (prev != null) {
prev.next = next; // cursor WeakOrderQueue对应的线程已经GC,则跳过该WeakOrderQueue
}
} else {
prev = cursor;
}
cursor = next;
} while (cursor != null && !success);
this.prev = prev;
this.cursor = cursor;
return success;
}
scavengeSome()方法的执行流程可以用下面这幅图表示:
Stack使用了head、prev、cursor三个指针指向了WeakOrderQueue链表。通过该链表就可以将其他线程保存的对象收割到Stack中。从scavengeSome()方法可以知道,只要从cursor指向的WeakOrderQueue中转移DefaultHandle对象成功,就返回true。下面看下具体的转移过程cursor.transfer(this)
:
// 将WeakOrderQueue中的handle对象转移至Stack,每次转移一个Link
boolean transfer(Stack<?> dst) {
Link head = this.head;
if (head == null) {
return false;
}
if (head.readIndex == LINK_CAPACITY) {
if (head.next == null) { // 没有Link对象了
return false;
}
this.head = head = head.next; // 更新head
}
final int srcStart = head.readIndex;
int srcEnd = head.get();
final int srcSize = srcEnd - srcStart;
if (srcSize == 0) { // Link无元素,返回false
return false;
}
final int dstSize = dst.size;
final int expectedCapacity = dstSize + srcSize;
if (expectedCapacity > dst.elements.length) {
final int actualCapacity = dst.increaseCapacity(expectedCapacity); // 扩容
// actualCapacity - dstSize: 当前可以传输的对象个数
srcEnd = min(srcStart + actualCapacity - dstSize, srcEnd);
}
if (srcStart != srcEnd) {
final DefaultHandle[] srcElems = head.elements;
final DefaultHandle[] dstElems = dst.elements;
int newDstSize = dstSize;
for (int i = srcStart; i < srcEnd; i++) {
DefaultHandle element = srcElems[i];
if (element.recycleId == 0) { // 未被回收过
element.recycleId = element.lastRecycledId;
} else if (element.recycleId != element.lastRecycledId) {
throw new IllegalStateException("recycled already");
}
srcElems[i] = null;
if (dst.dropHandle(element)) { // 判断是否丢弃该handle
// Drop the object.
continue;
}
element.stack = dst; // 绑定Stack
dstElems[newDstSize ++] = element;
}
if (srcEnd == LINK_CAPACITY && head.next != null) {
// Add capacity back as the Link is GCed.
reclaimSpace(LINK_CAPACITY); // 释放可分配空间
this.head = head.next;
}
head.readIndex = srcEnd; // 读到srcEnd
if (dst.size == newDstSize) { // 未收割任何DefaultHandle
return false;
}
dst.size = newDstSize;
return true;
} else {
// The destination stack is full already. Stack已满
return false;
}
}
从transfer()方法可知,每次调用该方法只会转移一个Link节点的对象。transfe r()方法逻辑比较简单,这里不再详述。
如果从其他线程的WeakOrderQueue收割DefaultHandle对象成功,则scavenge()
方法返回true。此时获取对象的pop()方法中,就可以获取到已回收的对象。
DefaultHandle<T> pop() {
int size = this.size;
if (size == 0) {
if (!scavenge()) { // 从其他线程的WeakOrderQueue回收DefaultHandle
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;
}
至此,异线程收割对象分析完毕。