1. 基础回顾
⑴主流的IO模型
①阻塞式I/O
当我们去买码头买鱼,鱼还没上来,我们一直在码头等着鱼钓上来,这就是同步阻塞I/O
②非阻塞式I/O
我们不断的问码头的鱼上来没有,上来我们就去拿,这就是同步非阻塞I/O,非阻塞IO模式下用户进程需要不断地询问内核的数据准备好了没有
③I/O多路复用
常用的IO多路复用方式有select、poll和epoll,通过一种机制,一个进程可以监视多个文件描述符(套接字描述符)一旦某个文件描述符就绪(一般是读就绪或者写就绪),能够通知程序进行相应的读写操作(这样就不需要每个用户进程不断的询问内核数据准备好了没)。
④信号驱动I/O
我们打个电话给渔夫,鱼准备好了通知我们去拿,这就是信号驱动式I/O模型
⑤异步I/O
我们打个电话给渔夫,鱼准备好了渔夫给你送过来,这就是异步非阻塞I/O
⑵select、poll和epoll的区别
①select:
时间复杂度O(n),它仅仅知道有I/O时间发生了,但不知道具体是哪个,所以要轮训所有的流。
当每次都去询问时,渔民会把所有你点的鱼都轮询一遍再告诉你情况,当大量鱼很长时间都不能准备好的情况下是很低效的
②poll
时间复杂度O(n),和select没有本质区别, 和select相比它没有最大连接数的限制,原因是它是基于链表来存储的
③epoll
时间复杂度O(1),epoll就是渔民每准备好一种鱼就记下来他。这样进程再去问的时候,他就不用挨个轮训了,直接告诉进程哪个好了,你再去拿。
⑶常见的调用模式
- Socket对象的阻塞模式属于阻塞式I/O
- Socket对象的非阻塞模式属于非阻塞式I/O
- Linux中的系统调用select函数属于I/O多路复用模型
- epoll系统调用则介于第三种和第四种模型之间
- 异步I/O很少有Linux系统支持,Windows系统提供了一个叫IOCP线程模型属于这一种
⑷特殊点
- Java的selector,selector 在Linux上的实现机制是epoll,而在Windows平台上的实现机制是select
⑸水平触发和边缘触发
①水平触发
用程序可以随时检查文件描述符的状态,然后再根据状态,进行 I/O 操作,比如select 或者 poll
②边缘触发
只有在文件描述符的状态发生改变(也就是 I/O 请求达到)时,才发送一次通知,比如epoll
2.java常见的IO模式
⑴BIO
适用于连接较少,对服务器资源消耗很大,但是编程简单。是同步阻塞的。
⑵AIO
适用于连接数量多而且连接时间长的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂,要注意设计。是异步非阻塞的
⑶NIO
使用于连接数量比较多且连接时间比较短的架构,比如聊天服务器,编程比较复杂。是同步非阻塞的
⑷NIO2
非阻塞异步IO
⑸Reactor模式
NIO框架的典型模式,Mina、Netty、Cindy都是此模式的实现。
①单线程
②多线程
③Multiple Reactor
3.Netty
netty其实对三种Java基本的Reactor模式都是支持的。我们前面演示过,netty启动时,要在ServerBootstrap中配置bossGroup和childGroup两个EventLoopGroup,也就是说netty是可以灵活配置的。我们通过配置可以让netty分别实现对三种模式的支持。