今天这是我在教室分享的一道面试题,怕忘记了自己花时间去研究了一下,看了大量的资料后整理的,不收藏你们就亏了哟。
这是个网络编程的面试题:
在讲 BIO,NIO,AIO 之前先来回顾一下这样几个概念:同步与异步,阻塞与非阻塞。
自己的理解:
也就是必须一件一件事做,等前一件做完了才能做下一件事 (提交请求->等待服务器处理->处理完返回 这个期间客户端浏览器不能干任何事 )
官方:
使用同步IO时,Java自己处理IO读写。
自己的理解:
请求通过事件触发->服务器处理(这是浏览器仍然可以作其他事情)->处理完毕
官方:
使用异步IO时,Java将IO读写委托给OS处理,需要将数据缓冲区地址和大小传给OS,完成后OS通知Java处理(回调)。
自己的理解:
阻塞就是说在煮水的过程中,你不可以去干其他的事情(性能和可靠性都不好)
官方:
使用阻塞IO时,Java调用会一直阻塞到读写完成才返回。
自己的理解:
非阻塞就是在同样的情况下,可以同时去干其他的事情(对于低负载、低并发的应用程序)
官方:
使用非阻塞IO时,如果不能立马读写,Java调用会马上返回,当IO事件分发器通知可读写时在进行读写,不断循环直到读写完成。
IO的方式通常分为几种,同步阻塞的BIO、同步非阻塞的NIO、异步非阻塞的AIO。
就是说服务端一旦接受客户端的连接,就可以建立通信套接字在这个通信套接字上进行读写操作,此时不能再接收其他客户端连接请求,只能等待同当前连接的客户端的操作执行完成,不过可以通过多线程来支持多个客户端的连接,循环导致高cpu消耗。
服务器的实现模式是一个连接一个线程,这样的模式很明显的一个缺陷是:
由于客户端连接数与服务器线程数成正比关系,可能造成不必要的线程开销,严重的还将导致服务器内存溢出。当然,这种情况可以通过线程池机制改善,但并不能从本质上消除这个弊端。
解决这个问题就有了下面的
从JDK1.4以后开始,JDK引入的新的IO模型NIO
而服务器的实现模式是多个请求一个线程,即请求会注册到多路复用器Selector上,多路复用器轮询到连接有IO请求时才启动一个线程处理。
Java NIO: 单线程管理多个连接。
劣处:维护成本高,容易出现bug,项目大了之后消耗成本
JDK1.7发布了NIO2.0也可以说是Nio的加强版,它是异步非阻塞的IO模型。
异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作。
这就是真正意义上的异步非阻塞,服务器的实现模式为多个有效请求一个线程,客户端的IO请求都是由OS先完成再通知服务器应用去启动线程处理(回调)。
应用场景:并发连接数不多时采用BIO,因为它编程和调试都非常简单,但如果涉及到高并发的情况,应选择NIO或AIO,更好的建议是采用成熟的网络通信框架Netty。
总结:理解了这,浓缩了还是有点东西的
BIO是一个连接一个线程。
NIO是一个请求一个线程。
AIO是一个有效请求一个线程。