您的位置 首页 java

Java NIO 与 IO

在学习java NIO和IO API中,大家的脑海里中会迅速弹出一个问题:

我应该什么时候使用 IO ,我应该什么时候使用NIO?

在本文中我将试图对java nio和IO之间的差异进行解读,它们的使用情况,以及它们是如何影响你的代码的设计。

Java NIO and IO不同之处

下表总结了java NIO和IO之间的主要差异。我将更详细地了解表后面各部分的不同之处。

IO NIO
面向流 面向缓冲
Blocking IO Non blocking IO
选择器

面向流与面向缓冲

java NIO和IO之间的第一个大的区别是,IO流为主,在NiO缓冲型。那是什么意思?

java的IO是面向流的意味着你读一个或多个字节在一个时间,从一个流。用读字节做什么取决于你自己。它们没有 缓存 在任何地方。此外,不能在流中的数据中来回移动。如果需要从流中读取的数据向前移动和返回,则需要先在缓冲区中缓存它。

java nio的缓冲型方法稍有不同。数据被读入缓冲区,稍后将处理它。您可以在缓冲区中来回移动。这使您在处理过程中具有更大的灵活性。但是,您还需要检查缓冲区是否包含所有需要的数据,以便完全处理它。而且,您需要确保在读取更多数据到缓冲区时,不会覆盖尚未处理的缓冲区中的数据。

Blocking 与 Non-blocking IO

java IO的各种流封闭。这意味着,当一个 线程 调用一个read()或write(),线程被封闭直到有数据读写数据,或是完全。线程在此期间不能做任何其他事情。

java nio的非封闭模式,使一个线程从一个信道请求读取数据,只有得到现有什么,或什么都没有,如果目前没有数据。在数据可以读取之前,不要封闭,线程可以继续使用其他的东西。

对于非封闭性写作也是如此。线程可以请求将某些数据写入通道,但不等待它被完全写入。然后线程可以继续,并在平均时间做其他事情。

线程在空闲时没有封闭IO调用,通常在其他通道上同时执行IO。也就是说,一个线程现在可以管理多个输入和输出通道。

选择器

java nio的选择器允许一个线程监听输入多通道。您可以用选择器注册多个通道,然后使用一个线程来“选择”具有可供处理的输入的通道,或者选择准备写入的通道。此选择器机制使单线程易于管理多个通道。

如何影响应用 程序设计

无论您是选择NIO还是IO,都可能影响应用程序设计的以下几个方面:

1.该API调用了。

2.数据处理。

3.用于处理数据的线程数。

API调用

当然,当使用不同于使用IO时的API时,API调用是不同的。这并不奇怪。而不仅仅是阅读从例如 InputStream 字节的数据字节,首先得将数据读入缓冲区,然后从那里被处理。

数据处理

使用纯NiO设计时,数据的处理也会受到影响,而不是IO设计。

在一个IO设计你读从InputStream或Reader字节数据字节。假设您正在处理基于行的文本数据流。例如:

Name: Tom
Age: 13
Email: 123456@139.com
Phone: 1234567890 

这样的文本行流可以像这样处理:

InputStream input = ... ; // get the InputStream from the client socket
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String nameLine = reader.readLine();
String ageLine = reader.readLine();
String emailLine = reader.readLine();
String phoneLine = reader.readLine(); 

注意程序的状态是由程序执行的程度决定的。换句话说,一旦前reader.readLine()个方法返回,您就可以确定已经读取了完整的文本行。readLine()个街区直到读完一整条线,这就是为什么。您还知道这行包含名称。类似地,当第二个readLine()调用返回时,您知道该行包含了年龄等。

正如你所看到的,程序只有在有新的数据读取时才能前进,而且每一步你都知道数据是什么。一旦执行线程在代码中读取某段数据之后,线程就不会在数据中倒退(主要不是)。这个原理也在这张图中得到了说明:

java IO:从流读取数据块。

一个NiO实现看起来不同。下面是一个简化的示例:

ByteBuffer buffer = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buffer); 

注意第二行读取通道进入缓冲区字节。当该方法调用返回时,您不知道所需的所有数据是否在缓冲区内。所有您知道的是,缓冲区包含一些字节。这使得处理更加困难。

想象一下,在第一次读(缓冲)调用之后,读入缓冲区的所有内容都是半行。例如,“名称:A”。你能处理那些数据吗?不是真的。你需要等到至少一系列数据已经进入缓冲区,才是有意义的过程,任何数据都。

那么,如何知道缓冲区是否包含足够的数据以便于处理呢?你不知道,唯一的方法是查看缓冲区中的数据。其结果是,你可能要在你知道的所有数据,检查数据缓冲区中的几次。这不仅效率低下,而且在程序设计方面可能会变得混乱。例如:

ByteBuffer buffer = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buffer);
while(! bufferFull(bytesRead) ) {
bytesRead = inChannel.read(buffer);
} 

bufferfull()方法记录多少数据读入缓冲区,并返回true或false,取决于缓冲区满。换句话说,如果缓冲区准备好进行处理,则它被认为是完整的。

bufferfull()方法扫描缓冲区,但必须离开缓冲在相同的状态,在被称为bufferfull()方法。如果没有,则读取到缓冲区的下一个数据可能不会在正确的位置读取。这不是不可能的,但这是另一个需要注意的问题。

如果缓冲区已满,则可以进行处理。如果它不是完整的,您可能可以部分处理任何数据,如果这在您的特殊情况下是有意义的。在许多情况下,它没有。

图中说明了缓冲区就绪循环中的数据:

Java NIO:从渠道到所有需要的数据在缓冲区中读取数据

总结

NiO允许你只使用一个(或几个)线程来管理多个通道(网络连接或文件),但代价是解析数据可能比从阻塞流读取数据要复杂得多。

如果你需要管理打开的连接同时成千上万,每个只发送一个小数据,例如一个聊天服务器,实现服务器在NiO的也许是一个优势。同样,如果您需要保持与其他计算机的大量开放连接,例如在P2P网络中,使用单个线程管理所有的出站连接可能是一个优势。这一个线程,多连接设计在图中有说明:

Java NIO:单线程管理多个连接

如果您的连接很少,带宽很高,每次发送大量数据,那么经典的IO服务器实现可能是最合适的。该图演示了一个典型的IO服务器设计:

Java IO:经典的IO服务器的设计-一个连接一个线程处理。

文章来源:智云一二三科技

文章标题:Java NIO 与 IO

文章地址:https://www.zhihuclub.com/188654.shtml

关于作者: 智云科技

热门文章

网站地图