通过一个无限循环,保证可以拿到所有的节点上的ByteBuf,通过这个函数获取节点,Object msg = in.current();
我们进一步看它的实现,如下,它只会取出我们标记的节点
下一步, 使用jdk的自旋锁,循环16次,尝试往jdk底层的ByteBuffer中写数据, 调用函数doWriteBytes(buf);他是本类的抽象方法, 具体的实现是,客户端chanel的封装类NioSocketChannel实现的源码如下:
// todo @Override protected int doWriteBytes(ByteBuf buf) throws Exception { final int expectedWrittenBytes = buf.readableBytes(); // todo 将字节数据, 写入到 java 原生的 channel中 return buf.readBytes(javaChannel(), expectedWrittenBytes); }这个readBytes()依然是抽象方法,因为前面我们曾经把从ByteBuf转化成了Dirct类型的, 所以它的实现类是PooledDirctByteBuf 继续跟进如下: 终于见到了亲切的一幕
// todo @Override public int readBytes(GatheringByteChannel out, int length) throws IOException { checkReadableBytes(length); //todo 关键的就是 getBytes() 跟进去 int readBytes = getBytes(readerIndex, out, length, true); readerIndex += readBytes; return readBytes; } 跟进getBytes(){ index = idx(index); // todo 将netty 的 ByteBuf 塞进 jdk的 ByteBuffer tmpBuf; tmpBuf.clear().position(index).limit(index + length); // todo 调用jdk的write()方法 return out.write(tmpBuf); } 此外,被使用过的节点会被remove()掉, 源码如下, 也是针对链表的操作 private void removeEntry(Entry e) { if (-- flushed == 0) { // todo 如果是最后一个节点, 把所有的指针全部设为 null // processed everything flushedEntry = null; if (e == tailEntry) { tailEntry = null; unflushedEntry = null; } } else { //todo 如果 不是最后一个节点, 把当前节点,移动到最后的 节点 flushedEntry = e.next; } } 小结到这里, 第二波任务的传播就完成了
write
将将buffer 转换成DirctBuffer
将消息entry 插入写队列
设置写状态
flush
刷新标志,设置写状态
变量buffer队列,过滤Buffer
调用jdk底层的api,把ByteBuf写入jdk原生的ByteBuffer