一、Java NIO 基本介绍
Java NIO全称Java non-blocking IO,是指JDK提供的新API。从JDK1.4开始,Java提供了一系列改进的输入/输出的新特性,被统称为NIO(即NewIO),是同步非阻塞的。NIO相关类都被放在java.nio包及子包下,并且对原java.io包中的很多类进行改写。NIO有三大核心部分:Channel(通道)、Buffer(缓冲区)、Selector(选择器) 。NIO是面向缓冲区,或者面向块编程的。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动,这就增加了处理过程中的灵活性,使用它可以提供非阻塞式的高伸缩性网络。Java NIO的非阻塞模式,使一个线程从某通道发送请求或者读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取,而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。非阻塞写也是如此,一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。- 通俗理解:
NIO是可以做到用一个线程来处理多个操作的。假设有10000个请求过来,根据实际情况,可以分配50或者100个线程来处理。不像之前的阻塞IO那样,非得分配10000个。
二、 NIO 和 BIO 的比较
BIO以流的方式处理数据,而NIO以块的方式处理数据,块I/O的效率比流I/O高很多。BIO是阻塞的,NIO则是非阻塞的。BIO基于字节流和字符流进行操作,而NIO基于Channel(通道)和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。Selector(选择器)用于监听多个通道的事件(比如:连接请求,数据到达等),因此使用单个线程就可以监听多个客户端通道。
三、 NIO 的流向说明
**理解:数据总是从通道读取到缓冲区中,或者从缓冲区写入到通道中。其实就是流向的问题,由下举例解释
如客户端服务端传输数据 站在服务端(程序)的角度看 ,数据是到程序里面来的所以是
**InputStream 对应的是 read , 过程是: 客户端数据===>通道===>然后把通道数据读取到缓冲区中===>我们从缓冲区中拿到数据进行程序设计**
如服务端(程序)给客户端(目标人物)传输数据,站在服务器(程序)的角度看.数据是从服务器出去的所以是
OutputStream 对应的是 write,过程是: 服务端数据===>把数据放在缓冲区中===>缓冲区数据写入到通道中===>客户端拿到数据进行业务处理
四、Selector、Channel 和 Buffer 关系图(简单版)

NIO的三大核心 : Selector、Channel 和 Buffer
图介绍:
- 每个
Channel都会对应一个Buffer。 Selector对应一个线程,一个线程对应多个Channel(连接)。- 该图反应了有三个
Channel注册到该Selector//程序 - 程序切换到哪个
Channel是由事件决定的,Event就是一个重要的概念。 Selector会根据不同的事件,在各个通道上切换。Buffer就是一个内存块,底层是有一个数组。- 数据的读取写入是通过
Buffer,这个和BIO,BIO中要么是输入流,或者是输出流,不能双向,但是NIO的Buffer是可以读也可以写,需要flip方法切换Channel是双向的,可以返回底层操作系统的情况,比如Linux,底层的操作系统通道就是双向的。五、 通俗讲述
原本以前的BIO 一个连接也就是得开辟出来一个线程进行读取,并且BIO中要么是输入流,要么是输出流,不能双向进行,这样无限制的开新线程处理连接,就算连接中什么事都没有干(读写),他这个线程还会在哪占用着资源。在高并发,高可用的应用场景中,这无疑是一种致命的操作,线程那么宝贵的资源,被无情浪费,就算用线程池进行管理线程也是亡羊补牢,没有什么大的实际解决。
经过分析了BIO的问题我总结3点:
1.线程、连接一对一
2.阻塞io
3.读取写入要么输入要么输出
NIO就是针对这3点问题进行完善,使用3个核心组件一一攻破,首先不再是一个线程对应一个连接,而是一个线程对应一个selector,然后一个selector可以被多个channel(连接)注册,通过Event(事件)轮询进行切换程序去处理哪一个clannel(连接),这样就把BIO的第一个第二个问题解决了。然后又引申出一个buffer概念,每一个clannel(连接)对应他们自己的buffer,把流处理接换成面向buffer或者说面向块处理,然后这样不仅解决了缓冲作用给性能又带来了优化,而且buffer还是双向的,通过buffer的flip方法反转一下buffer,就可以轻松解决读写的问题,不再像BIO那样读就是读、写就是写。
