Tomcat Endpoint
概要
I/O模型
- 同步阻塞I/O
- 同步非阻塞I/O
- I/O多路复用
- 异步 I/O
NioEndPoint
- Acceptor
- Poller
- SocketProcessor
I/O模型
UNIX 系统下的 I/O 模型有 5 种:
同步阻塞 I/O
同步非阻塞I/O
I/O多路复用
信号驱动I/O(不了解)
异步I/O
所谓I/O,就是计算机内存与外部设备之间拷贝数据的过程。
JAVA I/O模型
当用记发起I/O操作后,经历2个步骤
用户线程等待内核将数据从网卡(外设)中拷贝到内核空间
内核将数据从内核空间拷贝到用户空间
1.同步阻塞I/O
- 用户线程发起read调用后就阻塞了,让出CPU。
- 内核等待网卡数据到来,把数据从网卡拷贝到内核空间,接着把数据拷贝到用户空间,再把用户线程叫醒
- 用户线程读取数据
2.同步非阻塞I/O
- 用户线程不断的发起read调用,数据没到内核空间时,每次都返回失败
- 内核等待网卡数据到来,把数据从网卡拷贝到内核空间
- 这一次read调用后线程开始阻塞。在等待数据从内核空间拷贝到用户空间,等数据到用户空间后再把线程叫醒
3.I/O多路复用
- 通过select询问内核数据是否已经到达,select()方法是阻塞的。
- 通过read调用命令内核把网卡的数据拷贝到用户空间下,在内核拷贝数据到用户空间的这段时间内线程是阻塞的。一般这种情况下都是用selector在一个死循环内来实现的。
之所以称为多路复用,是因为一个selector可以询问多个连接的数据是否已经到达。
4.异步 I/O
- 用户线程发起 read 调用的同时注册一个回调函数,,read 立即返回,
- 等内核将数据准备好后,再调用指定的回调函数完成处理,在这个过程中,用户线程一直没有阻塞
NioEndPoint
它有三大线程组分别用于处理不同的逻辑:
Acceptor
线程:负责监听请求,等待和接收客户端连接。在接收到连接后,创建SocketChannel并将其注册到poller线程。Poller
线程:将SocketChannel放到selector上注册读事件,轮询selector,获取就绪的SelectionKey,并将就绪的SelectionKey(或SocketChannel)委托给工作线程。SocketProcessor
(work):执行真正的业务逻辑。
Acceptor线程和poller线程之间有一个SocketChannel队列,Acceptor线程负责将SocketChannel推送到队列,poller线程负责从队列取出SocketChannel。poller线程从队列取出SocketChannel后,紧接着会把它放到selector上注册读事件。
1 | public class NioEndpoint { |
NioEndPoint的启动,最主要是创建Acceptor线程池,同时监听新请求。