NIO学习笔记

NIO的三个核心组件,Buffer缓冲器,Channel通道,Selector选择器。

Buffer缓冲器

缓冲区本质上是一个可以写入数据的内存块(类似数组),然后可以再次读取。此内存块包含在NIO Buffer对象中,该对象提供了一组方法,可以更轻松地使用内存块。 相比较直接对数组的操作,BufferAPI更加容易操作和管理。 使用Buffer进行数据写入与读取,需要进行如下四个步骤:

  1. 将数据写入缓冲区。
  2. 调用buffer.flip(),转换为读取模式
  3. 缓冲区读取数据
  4. 调用buffer.clear()或buffer.compact()清除缓冲区
    NIO学习笔记
    ByteBuffer为性能关键型代码提供了直接内存(direct堆外)和非直接内存(heap堆)两种实现。
    堆外内存获取的方式:ByteBuffer directByteBuffer=ByteBuffer.allocateDirect(noBytes);

堆外内存可以降低一次数据拷贝操作,因为JVM会进行GC,GC时会移动对象的地址。所以JVM会先把数据复制到堆外,再进行写入,如果放在堆内,则还是要移动到堆外,所以直接用堆外内存就减少了一次拷贝。

DirectByteBuffer中有一个Cleaner对象(PhantomReference),Cleaner被GC前会执行clean方法,触发DirectByteBuffer中定义的Deallocator。

建议:
1、性能确实可观的时候才去使用;分配给大型、长寿命;(网络传输、文件读写场景)
2、通过虚拟机参数MaxDirectMemorySize限制大小,防止耗尽整个机器的内存;

Channel通道
NIO学习笔记
NIO学习笔记
SocketChannel替代了Socket的读和写,相当于更加简洁了,只需要创建一个通道后就可以进行读写操作,需要注意的是:

  1. write写:write()在尚未写入任何内容时就可能返回了。需要在循环中调用write()
  2. read读:read()方法可能直接返回而根本不读取任何数据,根据返回的int值判断读取了多少字节

ServerSocketChannel可以监听新建的TCP连接通道,类似ServerSocket。
NIO学习笔记
serverSocketChannel.accept():如果该通道处于非阻塞模式,那么如果没有挂起的连接,该方法将立即返回null。必须检查返回的SocketChannel是否为null。

先将所有连接放入一个List里面,如果没有连接进来,则进行List遍历读取,如果没有数据了则进行下一次遍历。
NIO学习笔记

Selector选择器

Selector是一个Java NIO组件,可以检查一个或多个NIO通道,并确定哪些通道已准备好进行读取或写入。实现单个线程可以管理多个通道,从而管理多个网络连接。

一个线程使用Selector监听多个channel的不同事件:
四个事件分别对应SelectionKey四个常量。
1.Connect 连接(SelectionKey.OP_CONNECT)
2.Accept 准备就绪(OP_ACCEPT)
3.Read 读取(OP_READ)
4.Write 写入(OP_WRITE)
NIO学习笔记
Selector的核心是事件驱动机制,更低层的技术为操作系统的多路复用。
NIO学习笔记
NIO学习笔记
NIO学习笔记
NIO对比BIO
NIO学习笔记