当前位置: 首页 > 面试题库 >

NIO (New I/O)

汤枫涟
2023-03-14
本文向大家介绍NIO (New I/O)相关面试题,主要包含被问及NIO (New I/O)时的应答技巧和注意事项,需要的朋友参考一下

2.1 NIO 简介

NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象

NIO中的N可以理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操作方法。 NIO提供了与传统BIO模型中的 SocketServerSocket 相对应的 SocketChannelServerSocketChannel 两种不同的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持一样,比较简单,但是性能和可靠性都不好;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可以使用同步阻塞I/O来提升开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发。

2.2 NIO的特性/NIO与IO区别

如果是在面试中回答这个问题,我觉得首先肯定要从 NIO 流是非阻塞 IO 而 IO 流是阻塞 IO 说起。然后,可以从 NIO 的3个核心组件/特性为 NIO 带来的一些改进来分析。如果,你把这些都回答上了我觉得你对于 NIO 就有了更为深入一点的认识,面试官问到你这个问题,你也能很轻松的回答上来了。

1)Non-blocking IO(非阻塞IO)

IO流是阻塞的,NIO流是不阻塞的。

Java NIO使我们可以进行非阻塞IO操作。比如说,单线程中从通道读取数据到buffer,同时可以继续做别的事情,当数据读取到buffer中后,线程再继续处理数据。写数据也是一样的。另外,非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。

Java IO的各种流是阻塞的。这意味着,当一个线程调用 read()write() 时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了

2)Buffer(缓冲区)

IO 面向流(Stream oriented),而 NIO 面向缓冲区(Buffer oriented)。

Buffer是一个对象,它包含一些要写入或者要读出的数据。在NIO类库中加入Buffer对象,体现了新库与原I/O的一个重要区别。在面向流的I/O中·可以将数据直接写入或者将数据直接读到 Stream 对象中。虽然 Stream 中也有 Buffer 开头的扩展类,但只是流的包装类,还是从流读到缓冲区,而 NIO 却是直接读到 Buffer 中进行操作。

在NIO厍中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的; 在写入数据时,写入到缓冲区中。任何时候访问NIO中的数据,都是通过缓冲区进行操作。

最常用的缓冲区是 ByteBuffer,一个 ByteBuffer 提供了一组功能用于操作 byte 数组。除了ByteBuffer,还有其他的一些缓冲区,事实上,每一种Java基本类型(除了Boolean类型)都对应有一种缓冲区。

3)Channel (通道)

NIO 通过Channel(通道) 进行读写。

通道是双向的,可读也可写,而流的读写是单向的。无论读写,通道只能和Buffer交互。因为 Buffer,通道可以异步地读写。

4)Selector (选择器)

NIO有选择器,而IO没有。

选择器用于使用单个线程处理多个通道。因此,它需要较少的线程来处理这些通道。线程之间的切换对于操作系统来说是昂贵的。 因此,为了提高系统效率选择器是有用的。

一个单线程中Selector维护3个Channel的示意图

2.3 NIO 读数据和写数据方式

通常来说NIO中的所有IO都是从 Channel(通道) 开始的。

  • 从通道进行数据读取 :创建一个缓冲区,然后请求通道读取数据。
  • 从通道进行数据写入 :创建一个缓冲区,填充数据,并要求通道写入数据。

数据读取和写入操作图示:

NIO读写数据的方式

2.4 NIO核心组件简单介绍

NIO 包含下面几个核心的组件:

  • Channel(通道)
  • Buffer(缓冲区)
  • Selector(选择器)

整个NIO体系包含的类远远不止这三个,只能说这三个是NIO体系的“核心API”。我们上面已经对这三个概念进行了基本的阐述,这里就不多做解释了。

2.5 代码示例

代码示例出自闪电侠的博客,原地址如下:

https://www.jianshu.com/p/a4e03835921a

为什么大家都不愿意用 JDK 原生 NIO 进行开发呢?从上面的代码中大家都可以看出来,是真的难用!除了编程复杂、编程模型难之外,它还有以下让人诟病的问题:

  • JDK 的 NIO 底层由 epoll 实现,该实现饱受诟病的空轮询 bug 会导致 cpu 飙升 100%
  • 项目庞大之后,自行实现的 NIO 很容易出现各类 bug,维护成本较高,上面这一坨代码我都不能保证没有 bug

Netty 的出现很大程度上改善了 JDK 原生 NIO 所存在的一些让人难以忍受的问题。

 类似资料:
  • NIO Framework 是对 Java NIO 库的封装,将NIO的复杂度隐藏起来。有了它,人们可以方便地实现安全,高性能的Java网络应用程序。

  • snake 百万级别的分布式游戏服务器实时通讯 NIO 框架 数据库建议:Ignite/cockroach 发现服务:Zookeeper 1. messagecreator: 基于Netty的Java消息对象池,基于Netty零拷贝专为Netty做优化。 长时间运行,消息池和Netty总内存占用不超过2G,不用考虑GC。 2. zk-common Zookeeper基础服务发现组件。 3. log

  • 问题内容: 我真的很麻烦:我想使用s和s 读取超过GB的巨大文件- 我发现的所有文档都暗示使用该方法映射文件相当简单。当然,由于所有Buffer方法都将int用于位置,限制和容量,因此限制为2GB,但是系统隐含的限制在那之下呢? 实际上,我遇到很多有关s 的问题!根本没有任何文件可以真正定义限制!因此- 如何在不获取异常的情况下将适合int-limit的文件安全地映射到一个或几个s中? 在尝试之前

  • 主要内容:1 创建一个AsynchronousFileChannel,2 读取数据,3 通过Future读取数据,4 通过CompletionHandler读取数据,5 写数据,5 通过Future写入数据,6 通过CompletionHandler写入数据在Java 7中,它AsynchronousFileChannel已添加到Java NIO。这样AsynchronousFileChannel 就可以从文件中异步读取数据,或将数据异步写入文件。本教程将说明如何使用AsynchronousFi

  • 主要内容:1 打开一个DatagramChannel,2 接收数据,3 发送数据,连接到特定地址Java NIO DatagramChannel是可以发送和接收UDP数据包的通道。由于UDP是无连接的网络协议,因此默认情况下,您不能仅从DatagramChannel其他通道读取和写入内容。相反,您发送和接收数据包。 1 打开一个DatagramChannel 这是打开方式DatagramChannel: 本示例打开一个DatagramChannel,它可以在UDP端口9999上接收数据包。

  • 主要内容:1 ServerSocketChannel的介绍,2 打开一个ServerSocketChannel,3 关闭ServerSocketChannel,4 监听传入的连接,5 非阻塞模式1 ServerSocketChannel的介绍 Java NIO ServerSocketChannel是一个通道,可以侦听传入的TCP连接,就像ServerSocket在标准Java Networking中一样。该ServerSocketChannel班位于java.nio.channels包。 这是