NIO和IO

什么是java的NIO

  • NIO(Non-Blocking I/O,java中,也称为New I/O),是一种同步非阻塞的I/O模型,也是I/O多路复用的基础,已经被越来越多地应用到大型应用服务器,是解决高并发、I/O处理问题的有效方式。
  • 同步非阻塞,服务器实现模式为一个线程处理多个请求(连接),即客户端发送的连接请求都会注册到多路复用器(Selector)上,多路复用器轮询到连接有 I/O 请求就进行处理。
  • 从JDK1.4开始,Java提供了一系列改进的输入/输出处理的新特性,被统称为NIO(即New I/O)。新增了许多用于处理输入输出的类,这些类都被放在java.nio包及子包下,并且对原java.io包中的很多类进行改写,新增了满足NIO的功能。
  • NIO采用内存映射文件的方式来处理输入输出,NIO将文件或文件的一段区域映射到内存中,这样就可以像访问内存一样访问文件了。NIO与原来的IO有同样的作用和目的,但是使用的方式完全不同, NIO支持面向缓冲区(Buffer)的、基于通道(Channel)的IO操作。NIO将以更加高效的方式进行文件的读写操作。

NIO中的三个重要组件:

  1. 缓冲区Buffer:缓冲区有直接缓冲区和非直接缓冲区之分,它实际上也是一段内存空间。在NIO库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,它也是写入到缓冲区中的。缓冲区的实质是一个数组,通常来讲它是一个字节数组。流程如下图:
    NIO和IO
  2. 通道Channel:Channel(通道)表示到实体如硬件设备、文件、网络套接字或可以执行一个或多个不同I/O操作的程序组件的开放的连接。
    Channel和传统IO中的Stream很相似。主要区别为:通道是双向的,通过一个Channel既可以进行读,也可以进行写;而Stream只能进行单向操作,通过一个Stream只能进行读或者写,比如InputStream只能进行读取操作,OutputStream只能进行写操作;通道是一个对象,通过它可以读取和写入数据,当然了所有数据都通过Buffer对象来处理。我们永远不会将字节直接写入通道中,相反是将数据写入包含一个或者多个字节的缓冲区。同样不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。
  3. 选择器Selector:Selector类是NIO的核心类,Selector(选择器)提供了选择已经就绪的任务的能力。Selector会不断的轮询注册在上面的所有channel,如果某个channel为读写等事件做好准备,那么就处于就绪状态,通过Selector可以不断轮询发现出就绪的channel,进行后续的IO操作。一个Selector能够同时轮询多个channel。这样,一个单独的线程就可以管理多个channel,从而管理多个网络连接。这样就不用为每一个连接都创建一个线程,同时也避免了多线程之间上下文切换导致的开销。

NIO&IO

核心区别:

  • NIO是以块的方式处理数据,但是IO是以最基础的字节流的形式去写入和读出的。所以在效率上的话,肯定是NIO效率比IO效率会高出很多。
  • NIO不在是和IO一样用OutputStream和InputStream 输入流的形式来进行处理数据的,但是又是基于这种流的形式,而是采用了通道和缓冲区的形式来进行处理数据的。
  • 还有一点就是NIO的通道是可以双向的,但是IO中的流只能是单向的。
  • 还有就是NIO的缓冲区(其实也就是一个字节数组)还可以进行分片,可以建立只读缓冲区、直接缓冲区和间接缓冲区,只读缓冲区很明显就是字面意思,直接缓冲区是为加快 I/O 速度,而以一种特殊的方式分配其内存的缓冲区。
  • 补充一点:NIO比传统的BIO核心区别就是,NIO采用的是多路复用的IO模型,普通的IO用的是阻塞的IO模型,两个之间的效率肯定是多路复用效率更高
  • 传统IO的弊端:传统IO就是工作的流程是当客户端发送消息的时候,会新建一个连接线程来处理连接,然后服务器端会有一个服务器线程(这个是无可避免的部分)来和客户端交互。但是我们可以这样想,当多并发连接的时候,会有很多个Thread,这样的线程无论客户端和服务器端是否进行通信都是存在的,会造成线程的开销很大。下面是一个展示的图,来展示一个BIO模式的工作流程:
    NIO和IO
  • 如果是采用NIO的话,中间会多加一个选择器(其实可以认为是多路复用器),选择器会选择去轮询下面连接,如果发现下游有事件连接,可以判断连接的具体事件,然后对这个连接进行选择并且处理。这样可以实现用一个线程对多个连接进行维护,减少线程的开销。
    NIO和IO
  • 当然,对于具体的业务,可能会出现有需要很多线程的情况,我们也可以建立多线程,这就是netty里面的group的思想,这里我就不展开讲了。
    NIO和IO
上一篇:Java NIO 中 Buffer 和 Channel 的简单介绍


下一篇:【总结】JavaIO