吃透Netty源码系列十三之ChannelOutboundBuffer详解
简单介绍
他是一个通道的出站缓冲区,所有要写的数据都会先存在这里,等到要刷新的时候才会真的写出去。
内部类Entry
其实消息都是封装成内部的Entry类的,存储结构是一个单链表。我来看看这个类,其实他是一个对象池,可以复用:
static final class Entry {
//Entry对象池
private static final ObjectPool<Entry> RECYCLER = ObjectPool.newPool(new ObjectCreator<Entry>() {
@Override
public Entry newObject(Handle<Entry> handle) {
return new Entry(handle);
}
});
private final Handle<Entry> handle;//池化操作的处理器
Entry next;//链表的下一个
Object msg;//信息
ByteBuffer[] bufs;//缓存字节缓冲区数组,为了复用提高效率
ByteBuffer buf;//缓存字节缓冲区,为了复用提高效率
ChannelPromise promise;//回调
long progress;//当前进度,即已经传了多少数据
long total;//总共的数据大小
int pendingSize;//待冲刷的评估大小,要加上96
int count = -1;
boolean cancelled;//是否被取消了
private Entry(Handle<Entry> handle) {
this.handle = handle;
}
//用对象池的方式创建实体
static Entry newInstance(Object msg, int size, long total, ChannelPromise promise) {
Entry entry = RECYCLER.get();//从池子里获取
entry.msg = msg;//消息
entry.pendingSize = size + CHANNEL_OUTBOUND_BUFFER_ENTRY_OVERHEAD;//评估的大小
entry.total = total;//具体大小
entry.promise = promise;
return entry;
}
//取消了,返回待冲刷的评估大小
int cancel() {
if (!cancelled) {
cancelled = true;//取消标识
int pSize = pendingSize;
// release message and replace with an empty buffer
ReferenceCountUtil.safeRelease(msg);//释放
msg = Unpooled.EMPTY_BUFFER;
pendingSize = 0;
total = 0;
progress = 0;
bufs = null;
buf = null;
return pSize;
}
return 0;
}
//用完初始化后再放回收到池子里
void recycle() {
next = null;//设置成null
bufs = null;
buf = null;
msg = null;
promise = null;
progress = 0;
total = 0;
pendingSize = 0;
count = -1;
cancelled = false;
handle.recycle(this);
}
//回收当前实体并获取下一个实体,为什么要先获取下一个再回收呢,因为回收的时候把next设置null啦
Entry recycleAndGetNext() {
Entry next = this.next;
recycle();
return next;
}
}
重要属性
static final int CHANNEL_OUTBOUND_BUFFER_ENTRY_OVERHEAD =//出站实体的额外开销96字节
SystemPropertyUtil.getInt("io.netty.transport.outboundBufferEntrySizeOverhead", 96);
//保存线程对应的缓冲区,默认是1024个ByteBuffer数组,FastThreadLocal比一般的ThreadLocal要快,他是利用数组,内部用的是常量索引的数组,不是hash算法
private static final FastThreadLocal<ByteBuffer[]> NIO_BUFFERS = new FastThreadLocal<ByteBuffer[]>() {
@Override
protected ByteBuffer[] initialValue() throws Exception {
return new ByteBuffer[1024];
}
};
// 单链表结构
// The Entry that is the first in the linked-list structure that was flushed
private Entry flushedEntry;//第一个要冲刷的实体
// The Entry which is the first unflushed in the linked-list structure
private Entry unflushedEntry;//第一个未冲刷的实体
// The Entry which represents the tail of the buffer
private Entry tailEntry;//尾结点实体
// The number of flushed entries that are not written yet
private int flushed;//要冲刷的数量,但是还没真正冲刷出去,就是出站缓冲区大小
private int nioBufferCount;//可以冲刷的缓冲区个数
private long nioBufferSize;//可以写出的总的缓冲区数组数据大小
private boolean inFail;//是否冲刷失败
//原子操作totalPendingSize
private static final AtomicLongFieldUpdater<ChannelOutboundBuffer> TOTAL_PENDING_SIZE_UPDATER =
AtomicLongFieldUpdater.newUpdater(ChannelOutboundBuffer.class, "totalPendingSize");
@SuppressWarnings("UnusedDeclaration")
private volatile long totalPendingSize;//待冲刷缓冲区的字节总数
//原子操作unwritable
private static final AtomicIntegerFieldUpdater<ChannelOutboundBuffer> UNWRITABLE_UPDATER =
AtomicIntegerFieldUpdater.newUpdater(ChannelOutboundBuffer.class, "unwritable");
@SuppressWarnings("UnusedDeclaration")
private volatile int unwritable;
private volatile Runnable fireChannelWritabilityChangedTask;//写能力改变的任务
decrementPendingOutboundBytes
减少待出站的字节数,默认是提交任务延迟触发的:
void decrementPendingOutboundBytes(long size) {
decrementPendingOutboundBytes(size, true, true);
}
private void decrementPendingOutboundBytes(long size, boolean invokeLater, boolean notifyWritability) {
if (size == 0)

本文深入剖析 Netty 中的 ChannelOutboundBuffer 类,详细介绍了其内部结构,包括 Entry 对象池、单链表存储结构、重要属性及方法。探讨了数据如何在写操作前缓存,并在刷新时实际写出的过程。
最低0.47元/天 解锁文章
1016

被折叠的 条评论
为什么被折叠?



