java NIO 的最佳实践( 三 )

ByteBuf使用ByteBuf,ByteBuffer对比
特性ByteBuffer1.有position,limit属性,通过flip()切换读写模式 ,不支持同时读/写 2.定长 3.直接内存ByteBuf1.有rix,wix,cap,maxCap属性,支持同时读/写 2.自动扩容 3.直接内存,堆内存,组合
建议使用ByteBuf
ByteBuf 的clear()和discardReadBytes()对比
现象: 使用clear()导致丢数据
原因: clear()实现通过 rix=wix=0,假如此时同时有数据写入,该部分数据则丢失
if (selectionKey.isWritable()) {while (writeBuffer.isReadable()) {ByteBuffer byteBuffer = writeBuffer.nioBuffer();channel.write(byteBuffer);writeBuffer.readerIndex(writeBuffer.readerIndex() + byteBuffer.position());int left = byteBuffer.limit() - byteBuffer.position();if (left != 0) {//无法一次性写入到缓冲区中,可能发生空转 break...break;} else { //清理已发送数据writeBuffer.clear();}}... }复制代码最佳实践:
使用discardReadBytes(),其通过arrayCopy方式并且线程安全,能够防止数据丢失.但频繁的arrayCopy会有性能问题. 可以使用clear()和discardReadBytes()的组合
if (selectionKey.isWritable()) {while (writeBuffer.isReadable()) {//当缓冲区使用>2/3事 且wix-rix< (maxCap*1/3) 对缓冲区进行整理if (writeBuffer.writerIndex() > (writeBuffer.maxCapacity() / 3 * 2) && writeBuffer.writerIndex() - writeBuffer .readerIndex() < (writeBuffer.maxCapacity() / 3)) { System.out.println(String.format("缓冲区使用超过2/3 discardReadBytes writerIndex:%d " + "readerIndex:%d", writeBuffer .writerIndex(), writeBuffer.readerIndex())); writeBuffer.discardReadBytes(); }ByteBuffer byteBuffer = writeBuffer.nioBuffer();channel.write(byteBuffer);writeBuffer.readerIndex(writeBuffer.readerIndex() + byteBuffer.position());int left = byteBuffer.limit() - byteBuffer.position();if (left != 0) {//无法一次性写入到缓冲区中,可能发生空转 break...//防止空转 等待下次write事件break;} else {//注意clear()的使用 因为writeBuffer一直在写入 writerIndex可能>readIndexif (writeBuffer.writerIndex() == writeBuffer.readerIndex()) {//TODO 因为不是原子过程 理论上会有问题 但实际验证中却没问题 待验证writeBuffer.clear();System.out.println("clear");}}}... }使用快速收敛在GunNetty中,快速收敛确保Selector中所有的key均为有效key,不包含失效key,该方法一般使用在关闭channel之后
@Overridepublic int fastLimit() throws IOException { bootSelector.wakeup(); return bootSelector.select(0);}1.如果正在阻塞轮训,立刻终止,使用wakeup函数
2.立刻select(0)删除已经失效的key




推荐阅读