说说什么是 NIO |Java 刷题打卡

本文正在参加「Java主题月 – Java 刷题打卡」,详情查看活动链接

一、前言

面试官:说说下什么是 NIO

凡凡:emmmmm,NIOJavaNIO 还是 I/O通信模型里?想坑劳资。。。
那先讲 I/O 吧,再引出 Java NIO,恩,就这样。。。
聊聊就聊聊。

图片名称

小算盘:

  • 那先 I/O 通信模型: BIONIOAIO
  • 再 为什么要 Java NIO
  • 最后,NIO 在网络上怎么用?selectepoll 也给管上。

二、BIONIOAIO

先来理解下:BIONIOAIO

  • BIO同步阻塞:每次操作卡在那,直到读写完成。但不是完全针对网络通信模型,同样适用磁盘文件的 IO 读写(FileInputStream

  • NIO同步非阻塞:非阻塞,通过 NIOFileChannel 发起个文件 IO 操作,发起之后就返回了,可以去干别的事; 同步,还是得不断的去轮询去问操作系统,干完没。

  • AIO异步非阻塞:非阻塞,通过 AIO 发起个文件 IO 操作后,立马可以返回干别的事了; 异步,操作系统自己干完 IO 后,再过来通知。

(1)BIO

BIO:同步阻塞式 IO,是最传统的网络通信模型。

BIO 网络通信方式:

  1. 服务端创建一个 ServerSocket
  2. 客户端创建一个 Socket 去连接 ServerSocket
  3. ServerSocket 接收到一个 Socket 连接请求,就创建一个 Socket 和 一个线程 去跟 客户端 Socket 通信。

客户端和服务端的 Socket ,进行同步阻塞式的通信:客户端 Socket 发送一个请求,服务端 Sokcet 进行处理后返回响应,响应必须是等处理完后才会返回。

如图:

nio.png

当然可以搞一个线程池,如图:

线程池,使用固定线程数量来处理请求。

但是高并发请求的时候,没有更多线程来处理,还是可能会导致各种排队和延时。

nio2.png

(2)NIO

JDK 1.4 中引入了 NIO,这是一种同步非阻塞的 IO,基于 Reactor 模型。

一些概念:

  • Buffer 缓冲区:一般将数据写入 Buffer 中,然后从 Buffer 中读取数据。

  • Channel 通道:NIO 中通过 Channel 来进行数据读写。

  • Selector 多路复用器:Selector 会不断轮询注册的 Channel,如果某个 Channel 上发生了读写事件,Selector 就会将这些 Channel 获取出来,就可以进行 IO 操作。

    一个 Selector 通过一个线程,就可以轮询成千上万的 Channel,这就意味着服务端可以接入成千上万的客户端。

如图:

nio3.png

(3)AIO

AIO:是基于 Proactor 模型的,就是异步非阻塞模型。

读请求:

  • 对应请求绑定 buffer,通知操作系统去异步完成读取
  • 期间,程序去干别的事
  • 操作系统干完了,回调接口,通知你去从 buffer 中读取数据

写请求:

  • 对应请求绑定 buffer,通知操作系统去异步完成写数据
  • 期间,程序去干别的事
  • 操作系统干完了,回调接口,通知你写完成了

三、Java NIO

为什么需要 NIO

多数 Java 应用程序已不再受 CPU 的束缚(把大量时间用在执行代码上), 而更改多时候是受 I/O 的束缚 (等待数据传输)。

操作系统 与 Java 基于流的 I/O 模型有些不匹配:

即: 操作系统喜欢整卡车运来数据, Java IO类 则喜欢一铲子一铲子地加工数据

  • 操作系统要移动的是大块数据 (缓冲区), 这往往是在硬件直接存储器存取 (DMA) 的协助下完成的。
  • JVMI/O类喜欢操作小块数据 — 单个字节、几行文本。
  • 结果是: 操作系统送来整个缓冲区的数据, Java IO的流数据类再花大量时间把它们拆成小块, 往往拷贝一小块就要往返于几层对象。

然后呢,有了 NIO, 就可以轻松地把一卡车数据备份到能直接使用的地方 (ByteBuffer)

了解 Java NIO,首先需要了解 三大重要组件:BufferChannelSelector

  • Selector:选择器用于监听多个通道的事件 (比如: 连接打开, 数据到达)

    因此, 单个线程可以监听多个数据通道。

  • Buffer :可当作成缓冲区,或中转站

  • Channel: 数据管道,用于在字节缓冲区和位于通道另一侧的实体 (通常是一个文件或套接字) 之间有效地传输数据

    基于通道(Channel) 和 缓冲区(Buffer)进行操作, 数据总是从通道读取到缓冲区中, 或者从缓冲区写入到通道中

多路复用是啥?NIO 做网络编程又是怎样耍的?

计算机网络领域的 I/O 多路复用:

  • 多路:指多条路
  • 复用:指多条连接复用同一个阻塞对象

这个阻塞对象和具体的实现有关,在 Linux 下:

  • 使用 select:公共阻塞对象就是 select 用到的 fd_set
  • 使用 epoll:就是 epoll_create 创建的文件描述符

I/O 多路复用技术归纳起来,有两个关键实现点:

  1. 当多条连接公用一个阻塞对象后,进程只需要一个阻塞对象上等待,而无须再轮询所有连接
  2. 当某条连接有新的数据可以处理时,操作系统会通知进程,进程从阻塞状态返回,开始业务处理

那么了解完多路复用,来看下 NIO 做网络编程又是怎么耍的?

NIO 网络编程,流程如下:

  1. 创建 Selector:这个就是阻塞对象

  2. 创建 ServerSocketChannel

    1.1 监听端口:例如 9000

    1.2 只对接收请求感兴趣,并将其注册到 Selector 上:即告诉 Selector 有接收请求就来通知我

  3. Selector 查询就绪事件并执行

  4. 客户端请求服务建立连接:

    3.1 与ServerSocketChannel 建立连接

    3.2 并将对应的 SocketChannel 注册到 Selector上:可能对读请求或者写请求感兴趣

    3.3 客户端与 SocketChannel 通信

如图:
java-nio.png

服务端,详细流程如下:

  1. 创建 Selector

  2. 创建 ServerSocketChannel ,监听端口,对接收请求感兴趣,并将其注册到 Selector

  3. Selector 查询就绪事件并执行

    • key 为连接请求,注册读:即刚建立完连接(TCP 三次握手),那么就需要读取 Header等信息

    • key 为可读,注册写:即读取客户端信息后,需要服务端返回客户端信息

      例如:建立完连接后,服务端就需要读取请求信息

    • key 为可写,注册读:即服务端返回客户端信息后,等待客户端下次读请求

      例如:服务端读取完请求的信息后,想把一些数据告诉客户端

java-nio2.png

代码略。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享