假设线程1创建了大量对象,线程2和线程3同时回收线程1的对象,当这两个线程第一次回收对象时会创建WeakOrderQueue,并将其添加到线程1的Stack。多个线程操控一个Stack,这就造成了竞争。那么netty是如何解决竞争?
代码
package study.recycler.again;
import io.netty.util.Recycler;
import java.util.concurrent.ConcurrentLinkedQueue;
/**
* 断点2 主线程回收池中会有大量CyclerA
*/
public class CycliMutiThread7 {
private static final Recycler<CyclerA> CyclerRecyclerA = new Recycler<CyclerA>() {
@Override
protected CyclerA newObject(Handle<CyclerA> handle) {
return new CyclerA(handle);
}
};
static final class CyclerA {
private String value;
public void setValue(String value) {
this.value = value;
}
private Recycler.Handle<CyclerA> handle;
public CyclerA(Recycler.Handle<CyclerA> handle) {
this.handle = handle;
}
public void recycle() {
handle.recycle(this);
}
}
private static final Recycler<CyclerB> CyclerRecyclerB = new Recycler<CyclerB>() {
@Override
protected CyclerB newObject(Handle<CyclerB> handle) {
return new CyclerB(handle);
}
};
static final class CyclerB {
private String value;
public void setValue(String value) {
this.value = value;
}
private Recycler.Handle<CyclerB> handle;
public CyclerB(Recycler.Handle<CyclerB> handle) {
this.handle = handle;
}
public void recycle() {
handle.recycle(this);
}
}
private static final Recycler<CyclerC> CyclerRecyclerC = new Recycler<CyclerC>() {
@Override
protected CyclerC newObject(Handle<CyclerC> handle) {
return new CyclerC(handle);
}
};
static final class CyclerC {
private String value;
public void setValue(String value) {
this.value = value;
}
private Recycler.Handle<CyclerC> handle;
public CyclerC(Recycler.Handle<CyclerC> handle) {
this.handle = handle;
}
public void recycle() {
handle.recycle(this);
}
}
public static void main(String[] args) throws InterruptedException {
ConcurrentLinkedQueue<CyclerA> qAThread = new ConcurrentLinkedQueue();
Thread t = Thread.currentThread();
for (int i = 0; i < 901; ++i) {
qAThread.add(CyclerRecyclerA.get());
}
Thread t1 = new Thread(() -> {
Thread temp = t;
CyclerA cyclerA = qAThread.poll();
cyclerA.setValue("t1");
cyclerA.recycle();
});
t1.start();
t1.join();
Thread t2 = new Thread(() -> {
Thread temp = t;
CyclerA cyclerA = qAThread.poll();
cyclerA.setValue("t2");
cyclerA.recycle();
});
t2.start();
t2.join();
System.out.println("over");//断点2
}
}
调用堆栈
setHead:528, Recycler$Stack (io.netty.util)
newQueue:358, Recycler$WeakOrderQueue (io.netty.util)
newWeakOrderQueue:705, Recycler$Stack (io.netty.util)
pushLater:688, Recycler$Stack (io.netty.util)
push:647, Recycler$Stack (io.netty.util)
recycle:236, Recycler$DefaultHandle (io.netty.util)
recycle:27, CycliMutiThread7$CyclerA (study.recycler.again)
lambda$main$0:80, CycliMutiThread7 (study.recycler.again)
run:-1, 440434003 (study.recycler.again.CycliMutiThread7$$Lambda$1)
run:748, Thread (java.lang)
关键代码
// Marked as synchronized to ensure this is serialized.
synchronized void setHead(WeakOrderQueue queue) {
queue.setNext(head);
head = queue;
}
由上面代码可以知道,netty中通过synchronized
保证多线程安全
此外Recycler
中还有Stack
中还有两个函数对理解整个流程(创建新的WeakOrderQueue
并将其添加到Stack
中)比较重要,下面会按照调用顺序讲解
private void pushLater(DefaultHandle<?> item, Thread thread) {
if (maxDelayedQueues == 0) {
// We don't support recycling across threads and should just drop the item on the floor.
return;
}
// we don't want to have a ref to the queue as the value in our weak map
// so we null it out; to ensure there are no races with restoring it later
// we impose a memory ordering here (no-op on x86)
Map<Stack<?>, WeakOrderQueue> delayedRecycled = DELAYED_RECYCLED.get();
WeakOrderQueue queue = delayedRecycled.get(this);
if (queue == null) {
if (delayedRecycled.size() >= maxDelayedQueues) {
// Add a dummy queue so we know we should drop the object
delayedRecycled.put(this, WeakOrderQueue.DUMMY);
return;
}
// Check if we already reached the maximum number of delayed queues and if we can allocate at all.
if ((queue = newWeakOrderQueue(thread)) == null) {
// drop object
return;
}
delayedRecycled.put(this, queue);
} else if (queue == WeakOrderQueue.DUMMY) {
// drop object
return;
}
queue.add(item);
}
比如线程2回收线程1创建的对象,首先会通过对象中注册的DefaultHandler
获取对象所属的Stack
,然后经过一系列判断进入到pushLater
这个函数中并进行下面操作。
线程2第一次回收线程1所创建的对象
1、调用DELAYED_RECYCLED.get()
获取一个ThreadLocal对象(如果没有就创建新的)
2、调用newWeakOrderQueue(thread)
创建并添加WeakOrderQueue
跟踪newWeakOrderQueue
的代码,可以看到WeakOrderQueue
的这个函数
static WeakOrderQueue newQueue(Stack<?> stack, Thread thread) {
// We allocated a Link so reserve the space
if (!Head.reserveSpaceForLink(stack.availableSharedCapacity)) {
return null;
}
final WeakOrderQueue queue = new WeakOrderQueue(stack, thread);
// Done outside of the constructor to ensure WeakOrderQueue.this does not escape the constructor and so
// may be accessed while its still constructed.
stack.setHead(queue);//上文提到过这个函数,用synchronized修饰过
return queue;
}
1、new WeakOrderQueue(stack, thread)
创建新的WeakOrderQueue
。其中入参thread
会存放到WeakOrderQueue.referent
中
2、上文提到过这个函数,WeakOrderQueue
放入Stack中。这个函数用synchronized
修饰过,以保证多线程安全。