0%

Java NIO底层原理

前言:最近在看dubbo框架底层依赖协议时注意到了java NIO,由于操作系统和I/O相关的底层原理一直没有好好研究过,感到一头雾水,于是决定写篇博客学习一下

Java IO读写原理

  • read系统调用

    是把数据从内核缓冲区复制到进程缓冲区

  • write系统调用

    把数据从进程缓冲区复制到内核缓冲区

  • kernal

    负责数据在内核缓冲区和磁盘之间的交换

java读写流程

  1. 客户端请求

    • Linux通过网卡,读取客户断的请求数据,将数据读取到内核缓冲区
  2. 获取请求数据

    • 服务器从内核缓冲区读取数据到Java进程缓冲区。
  3. 服务器端业务处理

    • Java服务端在自己的用户空间中,处理客户端的请求。
  4. 服务器端返回数据

    • Java服务端已构建好的响应,从用户缓冲区写入系统缓冲区。
  5. 发送给客户端

    • Linux内核通过网络 I/O ,将内核缓冲区中的数据,写入网卡,网卡通过底层的通讯协议,会将数据发送给目标客户端。

同步阻塞

"同步阻塞"
用户线程在系统调用的整个IO过程中都是阻塞的(1.等待数据到达内核缓冲区 2.将数据拷贝)

同步非阻塞

"同步非阻塞"
用户线程在系统调用的

  1. 等待数据到达内核缓冲区(kernal buffer) 非阻塞
  • 在内核缓冲区没有数据的情况下,系统调用会立即返回,返回一个调用失败的信息
  • 用户线程需要不断的发起 I/O调用 同时可以做别的处理
  1. 拷贝数据到用户缓冲区(user buffer) 阻塞

多路复用模型

"多路复用"

  1. 进行select/epoll系统调用,查询可以读的连接。kernel会查询所有select的可查询socket列表,当任何一个socket中的数据准备好了,select就会返回。
    当用户进程调用了select,那么整个线程会被block(阻塞掉)。
  2. 用户线程获得了目标连接后,发起read系统调用,用户线程阻塞。内核开始复制数据。它就会将数据从kernel内核缓冲区,拷贝到用户缓冲区(用户内存),然后kernel返回结果。
  3. 用户线程才解除block的状态,用户线程终于真正读取到数据,继续执行。

多路复用的两种模式

"多路复用1"
"多路复用2"

优点: 用select/epoll的优势在于,它可以同时处理成千上万个连接(connection)。与一条线程维护一个连接相比,I/O多路复用技术的最大优势是:系统不必创建线程,也不必维护这些线程,从而大大减小了系统的开销

异步非阻塞

"异步非阻塞"

AIO的基本流程是:用户线程通过系统调用,告知kernel内核启动某个IO操作,用户线程返回。kernel内核在整个IO操作(包括数据准备、数据复制)完成后,通知用户程序,用户执行后续的业务操作。