一、是什么
NIO:(non-bloking IO)非阻塞IO,为所有的原始类型提供缓存(buffer)支持。字符集编码解码解决方案。支持锁和内存映射文件的文件访问接口。提供多路非阻塞式的高伸缩性网络IO。(果然官网上都是一些非人类的东西)。
IO:广义的IO指的是计算机与外部世界或者是程序与计算器其他部分的接口。狭义上Java里的IO只的是面向流的老IO接口。
1.1、BIO、NIO和AIO的区别
BIO:一个连接一个线程,客户端有连接请求时服务器端就需要启动一个线程进行处理。线程开销大。
伪异步IO:将请求连接放入线程池,一对多,但线程还是很宝贵的资源。
NIO:一个请求一个线程,但客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。
AIO:一个有效请求一个线程,客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理,
BIO是面向流的,NIO是面向缓冲区的;BIO的各种流是阻塞的。而NIO是非阻塞的;BIO的Stream是单向的,而NIO的channel是双向的。
NIO的特点:事件驱动模型、单线程处理多任务、非阻塞I/O,I/O读写不再阻塞,而是返回0、基于block的传输比基于流的传输更高效、更高级的IO函数zero-copy、IO多路复用大大提高了Java网络应用的可伸缩性和实用性。基于Reactor线程模型。
在Reactor模式中,事件分发器等待某个事件或者可应用或个操作的状态发生,事件分发器就把这个事件传给事先注册的事件处理函数或者回调函数,由后者来做实际的读写操作。如在Reactor中实现读:注册读就绪事件和相应的事件处理器、事件分发器等待事件、事件到来,激活分发器,分发器调用事件对应的处理器、事件处理器完成实际的读操作,处理读到的数据,注册新的事件,然后返还控制权。
BIO较之NIO的最大问题是前者严重依赖于线程。但线程是很”贵”的资源,主要表现在:
线程的创建和销毁成本很高,在Linux这样的操作系统中,线程本质上就是一个进程。创建和销毁都是重量级的系统函数。
线程本身占用较大内存,像Java的线程栈,一般至少分配512K~1M的空间,如果系统中的线程数过千,恐怕整个JVM的内存都会被吃掉一半。
线程的切换成本是很高的。操作系统发生线程切换的时候,需要保留线程的上下文,然后执行系统调用。如果线程数过高,可能执行线程切换的时间甚至会大于线程执行的时间,这时候带来的表现往往是系统load偏高、CPU sy使用率特别高(超过20%以上),导致系统几乎陷入不可用的状态。
容易造成锯齿状的系统负载。因为系统负载是用活动线程数或CPU核心数,一旦线程数量高但外部网络环境不是很稳定,就很容易造成大量请求的结果同时返回,激活大量阻塞线程从而使系统负载压力过大。
二、有什么用
NIO的引入是为了实现高速的IO功能。
传统IO是通过数据流和序列化实现系统输入和输出。数据流都继承自InputStream和OutputStream。阻塞式IO,当一个线程调用read()或者write()实现IO功能时,该线程会被阻塞,知道有一些数据被读取或者数据完全写入,而不能干其他事。IO面向流意味着每次从流中读取一个或者多个字节,直至读取所有的字节,没有被缓存。另外不能前后移动流中的数据,如果需要前后移动从流中读取数据,需要先将他缓存到另一个缓冲区。
NIO是基于通道和缓冲区的 I/O 方式。是一种同步非阻塞的 IO 模型。同步是指线程不断轮询 IO 事件是否就绪,非阻塞是指线程在等待 IO 的时候,可以同时做其他任务。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。NIO面向缓冲是想数据读取到一个缓冲区供后续使用,可以在缓冲区中前后一定数据。
三、怎么用
通道和缓冲区是NIO的核心对象。网络传输时的过程:用户数据——>发送端缓冲——>发送端Channel——>网络传输——>接收端Channel——>接收端缓冲——>用户数据。
任何写入写出的数据都要通过通道(channel)对象。可以通过它读取和写入数据,类似于IO里的流。Channel就像一个管道一样,将数据在管道两端的字节缓冲之间进行高效率的传输。它就像是一个网关,通过它可以用最小的成本来访问操作系统本地的I/O服务,而缓冲则是在两端内部的端点,Channel使用它来发送和接收数据。包括FileChannel、ServerSocketChannel、SocketChannel、DatagramChannel。
缓冲区(buffer)实际是一个数据容器对象。发送给一个通道的所有对象都必须首先放到缓冲区中;从通道中读取的任何数据都要读到缓冲区中。缓冲区实质上是一个数组。通常它是一个字节数组,但是也可以使用其他种类的数组。但是一个缓冲区不 仅仅 是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程。
四、深入研究方向
选择器(Selector)提供了挑选可用状态Channel的能力,从而实现多路复用的I/O。选择器能够检测一到多个NIO通道,并能够知晓通道是否为诸如读写事件做好准备的组件。这样,一个单独的线程可以管理多个channel,从而管理多个网络连接。
4.1、AIO
4.2、NIO和IO底层具体实现方式
4.3、四类channel的异同
- FileChannel:从文件中读写数据。
- DatagramChannel:能通过UDP读写网络中的数据。
- SocketChannel:能通过TCP读写网络中的数据。
- ServerSocketChannel:可以监听新进来的TCP连接,像Web服务器那样。对每一个新进来的连接都会创建一个SocketChannel。
4.4、NIO和epoll
五、面试点