上一节说了NIOEndpoint,其实现了IO多路复用,也就是同步非阻塞的方式。那么今天就来说说NIO2Endpoint,它跟NIOEndpoint的区别就是它实现了IO异步非阻塞。
首先先来说说什么是IO多路复用以及异步非阻塞。
-
IO多路复用
线程读取请求的数据分为两步。第一步就是通过select询问内核数据是否已经到达;若数据已到达,第二步就是通过read调用命令内核把网卡的数据拷贝到用户空间下,在内核拷贝数据到用户空间的这段时间内线程是阻塞的。一般这种情况下都是用selector在一个死循环内来实现的。之所以称为多路复用,是因为一个selector可以询问多个连接的数据是否已经到达。 -
异步非阻塞
用户线程发起read请求内核读取数据时会同时传入一个回调函数,此时线程不用等待。当数据到达网卡后,内核会自动把数据拷贝到用户空间下并调用回调函数。NIO2Endpoint由LimitLatch,Acceptor,SocketProcessor,Nio2SocketWrapper和Executor五部分组成。从中可以看到,比NIOEndpoint少了Poller组件,是因为NIO2Endpoint该模式为异步非阻塞,不需要一个Selector去读取网卡的数据。
-
LimitLatch
和NIOEndpoint的LimitLatch相同,这里不再赘述。如果还没搞清楚LimitLatch,可以翻看上一片博客。 -
Acceptor
和NIOEndpoint的Acceptor大体相同,唯一的不同就是在setSocketOptions方法内。它不是通过调用Poller来把SocketWrapper放到线程池中执行,而是直接把SocketWrapper放到线程中执行。 -
SocketProcessor
和NIOEndpoint的SocketProcessor相同,这里不再赘述。如果还没搞清楚SocketProcessor,可以翻看上一片博客。 -
Executor
和NIOEndpoint的Executor相同,这里不再赘述。如果还没搞清楚Executor,可以翻看上一片博客。 -
Nio2SocketWrapper
这里得详细说说Nio2SocketWrapper。NIO2Endpoint实现异步非阻塞的主要功能都是在Nio2SocketWrapper中完成的。Nio2SocketWrapper有两个内部类,分别为ScatterReadCompletionHandler和GatherWriteCompletionHandler。它们都实现了CompletionHandler,所以它们才能作为回调函数传入到内核中。它们的作用分别是从网卡中读取数据和把数据写回到网卡中。