参考链接:https://www.leahy.club/archives/netty-nio-sync-nonblocking

这个问题可以分为两部分:NIO为什么是同步非阻塞的?Netty是如何实现NIO的?
那么首先需要回答是什么是同步/异步,什么是阻塞/非阻塞?
同步/异步和阻塞/非阻塞描述的都是IO操作。

同步和异步:

从操作系统角度来说,网络IO的数据拷贝主要分为两个阶段,一是数据准备阶段,二是数据从内核拷贝到用户中。

同步IO指的是数据从内核拷贝到用户时。发起该请求的线程会自己来拷贝数据(表现为线程阻塞拷贝)。

PS:一旦涉及到网络 IO必定会发生数据拷贝的阻塞(此阻塞非彼阻塞,这里的阻塞形容的是拷贝数据相对于CPU的速度来说是非常耗时的,看起来像线程阻塞了一样。我们常说的阻塞是线程挂起并让出CPU),只不过阻塞发生在其他的地方(自己来拷贝就是同步的,别人帮我拷贝就是异步的),因为IO必定会用到CPU,即使是零拷贝。

阻塞和非阻塞:

阻塞和非阻塞主要描述的是网络IO数据拷贝的第一个阶段。

阻塞指的是线程一直等待数据准备好,期间什么都不干,但是会让出CPU,这样其他线程可以执行(CPU的利用率比较高),数据准备好之后自己来拷贝数据。

非阻塞指的是在第一阶段,发起网络IO请求的时候会立即返回去干别的事情,但是会不断地进行询问数据是否准备好,这种方式称之为轮询。由于CPU要处理更多的系统调用(每次询问都是系统调用),这种模型的CPU利用率低。

同步IO包括阻塞IO、非阻塞IO和IO多路复用。


NIO是如何实现同步非阻塞的呢?

Java的NIO实现采用了同步非阻塞IO和IO多路复用,其核心组件是Selector。Selector会不断的主动的询问Channel是否有事件发生,有事件发生,会进行事件处理。

//java nio
while(true) {
  ......
  selector.select(1); //不阻塞
  Set<SelectionKey> selectionKeySet= selector.selectedKeys();
  ......
  //处理selectionKeySet中事件,线程没有阻塞
}

//java socket处理连接,线程会阻塞
while(true) {
  ......
  Socket socket = serverSocket.accept(); //阻塞
  InputStream in = socket.getInputStream(); 
  ......
  //处理in中内容
}

Netty采用的是NIO其对Java的NIO进行了改进,其内部也封装了Selector和Channel,采用串行并发来提高效率。

Java的NIO采用的是Reactor线程模型中的单Reactor单线程模型(前台和服务员是一个人,全程为顾客服务,可以服务多个人),Netty的NIO采用的是主从Reactor模型,是多Reactor多线程模型。


Netty中常说的NIO与Netty的异步事件有什么关系?

没有关系。

Netty是异步事件驱动的框架,网络IO模型采用的是NIO(同步非阻塞IO)。异步事件驱动框架体现在所有的I/O操作是异步的,所有的IO调用会立即返回,并不保证调用成功与否,但是调用会返回ChannelFuturenetty会通过ChannelFuture通知你调用是成功了还是失败了亦或是取消了。

io.netty.channel.Channel类的一段注释请参考。

All I/O operations are asynchronous.
All I/O operations in Netty are asynchronous. It means any I/O calls will
return immediately with no guarantee that the requested I/O operation has
been completed at the end of the call. Instead, you will be returned with
a {@link ChannelFuture} instance which will notify you when the requested I/O
operation has succeeded, failed, or canceled.

所以所谓的异步是针对用户而言的,用户使用Channel进行IO操作,会立即返回。但是这个IO操作的任务是提交给了Netty的NIO底层去进行处理,所以我们说Netty的异步事件驱动与Netty底层基于NIO(同步非阻塞)是不矛盾的。


参考链接:

介绍了操作系统底层的IO模型

Netty的异步事件驱动?NIO?