最后更新时间:2014-06-23
当学习Java NIO和IO的API的时候,一个问题很快的就会出现中我们的脑中:
我什么时候应该使用IO,什么时候应该使用NIO?
在这篇文章中我将会尝试着写出中NIO和IO之间不同的地方,他们的使用场景,以及他们怎么影响你的代码设计。
Java NIO和IO的主要不同
下面的表格总结了Java NIO和IO的主要不同。针对这个表格中的不同点我将会给予更加详细的说明。
IO | NIO |
基于流的 | 基于缓冲区的 |
堵塞IO | 非堵塞IO |
Selectors(选择器) |
基于流的相对基于缓冲区的
在Java NIO和IO之间第一个最大的不同就是,IO是基于流式的,而NIO是基于缓冲区的。这样是意味着什么呢?
基于流式的Java IO意味着你每次是从一个流中读取一个或者更多的字节。处理这个读到的字节取决于你。他们不能在任何地方被缓存。并且,在流中的数据你不能向前或者返回。如果你需要去向前或者返回去读取一个流中的数据,你将会首先需要把它缓存中buffer中。
Java NIO基于缓冲区的方式稍微有些不同。数据读进一个缓冲区中,然后后面会被处理。你可以按照你需要的在缓冲区中向前或者返回。这个中处理期间给予更大的灵活性。然而,你也需要去检查这个缓冲区中是否包含你需要处理的所有数据。而且,你需要确认什么时候可以读取更多的数据进入到缓冲区,你不能覆盖掉还没有处理的缓冲区的数据。
堵塞相对非堵塞IO
Java IO的各种流是堵塞的。那就意味着,当一个线程调用read()方法或者write()方法的时候,那个线程将会被堵塞直到这里有数据可以读,或者有数据可以被写。在此期间,这个线程不能做其他任何事情。
Java NIO的非堵塞模式可以让一个线程从一个通道中发送读数据请求,并且只是得到当前可用的,或者如果当前没有数据可用,那就什么都没有。而不是保持锁定直到有数据可读,这个线程可以继续去做其他的事情。
对于非堵塞写也是相同的。一个线程可以发送一个写数据到通道的请求,但是不会等到它完全被写。这个线程然后继续的同时去做其他事情。
当非堵塞IO调用的时候,线程花费他们空闲的时间在什么地方?通常是同时在其他的通道中执行IO。那就是,一个单独的线程可以管理多个通道的输入和输出。
选择器(Selectors)
Java NIO的选择器允许一个单独的线程去监控多个通道的输入。你可以用一个选择器注册多个通道,然后使用一个单线程去“选择”对于进程有可用输入的通道,或者“选择”准备好写的通道。这个选择器原理使得单个线程去管理多个通道变得简单了。
NIO和IO是怎样影响应用设计
不管你选择NIO还是IO作为你的工具包可能都会影响你应用设计的各个方面:
Name: Anna Age: 25 Email: [email protected] 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方法调用返回了,你知道这行包含了年龄等等。
ByteBuffer buffer = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buffer);注意第二行,是从通道中读取字节到ByteBuffer中。当那个方法调用返回的时候,你不知道是否你需要的所有数据在这个缓冲区中。所有你知道的只是这个缓冲区包含了一些字节。这样就会使得处理有点困难。
ByteBuffer buffer = ByteBuffer.allocate(48); int bytesRead = inChannel.read(buffer); while(! bufferFull(bytesRead) ) { bytesRead = inChannel.read(buffer); }这个bufferFull()的方法不得不跟踪有多少数据读到缓冲区了,并且根据缓冲区是否满了返回true或者false。换句话说,如果缓冲区准备好处理了,它就是认为满了。
翻译地址:http://tutorials.jenkov.com/java-nio/nio-vs-io.html