服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理

服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理
image.png

  • 可以用极少的线程处理很多的连接, 因此在内存管理和上下文切换上的开销很低
  • 当没有io操作时,线程可以去处理其它的事

这套API由三个主要的部分组成:缓冲区(Buffers)、通道(Channels)和选择器(Selectors)组成。

Channel通道

与一个实体的连接; 实体可以是硬件设备, 文件, 网络socket,执行读写的程序块

Buffer缓冲区

NIO (non-blocking IO/New IO) 同步非阻塞 - 图2> 内存中预留指定字节数的存储空间用来对输入/输出(I/O)的数据作临时存储,这部分预留的内存空间就叫做缓冲区

DirectBuffer

  • 减少了垃圾回收
  • 加快了复制的速度
  • 使用了堆外内存就间接失去了JVM管理内存的可行性,改由自己来管理,当发生内存溢出时排查起来非常困难

    HeadBuffer

  • HeadBuffer在发送给socket需要先拷贝到DirectBuffer里面, 速度较慢

  • JVM可以管理这部分内存

Selector选择器

Selector 允许一个单一的线程来操作多个 Channel
image.png
image.png

NIO SelectionKey中定义的4种事件

  • SelectionKey.OP_ACCEPT: 接收连接继续事件,表示服务器监听到了客户连接,服务器可以接收这个连接了, 只有ServerSocketChannel需要注册这个事件
  • SelectionKey.OP_CONNECT: 连接就绪事件,表示客户与服务器的连接已经建立成功, 只有SocketChannel需要注册这个事件
  • SelectionKey.OP_READ: 读就绪事件,表示通道中已经有了可读的数据,可以执行读操作了(通道目前有数据,可以进行读操作了)
  • SelectionKey.OP_WRITE: 写就绪事件,表示已经可以向通道写数据了(通道目前可以用于写操作). 通道在空闲的时候都是可写的, 基本上有99%的时间都是可写的, 因此在发送数据时,如果因为通道的阻塞,暂时不能全部发送,才注册写事件。等通道可写时,再写入。同时判断是否写完,如果写完,就取消写事件即可。