吃透Netty源码系列十三之ChannelOutboundBuffer详解

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

简单介绍

他是一个通道的出站缓冲区,所有要写的数据都会先存在这里,等到要刷新的时候才会真的写出去。

内部类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) 
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值