问:Java 的 IO 和 NIO 有什么差异?
答:Java 的 IO 主要面向流、阻塞式 IO,而 JDK 1.4 提供的 NIO (New IO) 主要面向缓冲、非阻塞式 IO、支持选择器操作。
IO 面向流的含义是说每次从流中读一个或多个字节默认是没有被缓存的,而且我们不能前后移动流中的数据(要前后移动从流中读取的数据需要先将它缓存到一个缓冲区)。
NIO 面向缓冲的含义是说数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动操作,这样可以增加处理过程的灵活性,不过我们需要检查该缓冲区中是否包含所有你需要处理的数据且需确保当更多的数据读入缓冲区时不要覆盖缓冲区里尚未处理的数据。
IO 流是阻塞的,也就是说当一个线程调用 read() 或 write() 方法时该线程会被阻塞,直到有一些数据被读取或写入。
NIO 是非阻塞的,也就是说当一个线程从某通道(注意,FileChannel 不支持非阻塞)进行数据读写时可以不用等待读到所有可用数据或完全写入数据就可以返回的特性。故一个线程可以将非阻塞 IO 的空闲时间用于在其它通道上执行非阻塞 IO 操作,也就是说一个单独的线程可以管理多个非阻塞的输入输出通道(Channel)。
NIO 的通道类似于 IO 流,但是支持异步读写数据,通道是双向的,而 IO 流是单向的,通道的数据总是要先读到一个 Buffer 或从一个 Buffer 写入通道。NIO 提供的主要通道类型如下:
FileChannel:
从文件中读写数据,比较特殊,可以与其他通道进行数据交互,不支持非阻塞模式。DatagramChannel:
通过 UDP 读写网络中的数据。SocketChannel:
通过 TCP 读写网络中的数据。ServerSocketChannel:
监听新进来的 TCP 连接,每个新进来的连接都会创建一个 SocketChannel。
缓冲区的本质是一块可以存储数据的内存,被封装成了 Buffer 对象,缓冲区的类型主要有 ByteBuffer、MappedByteBuffer、CharBuffer、DoubleBuffer、FloatBuffer、IntBuffer、LongBuffer、ShortBuffer
几种,常用方法支持分配一块缓冲区、向缓冲区读写数据、切换缓冲区从写模式到读模式、清除缓冲区、做标记与复位等。
NIO 的选择器(Selector)允许一个单独的线程来监视多个通道,我们可以注册多个通道使用一个选择器,然后使用一个单独的线程来非阻塞轮询这些通道。IO 不支持这个特性,因为其为阻塞式。
选择器的本质相当于一个观察者,用来监听通道感兴趣的事件,一个选择器可以绑定多个通道,通道向选择器注册时需要指定感兴趣的事件,选择器支持的事件有 SelectionKey.OP_CONNECT、SelectionKey.OP_ACCEPT、SelectionKey.OP_READ、SelectionKey.OP_WRITE
,多个事件可以通过位或组合。
本文参考自 IO 与 NIO 区别相关面试题解析