十四、Java NIO 和 IO

所有文章

https://www.cnblogs.com/lay2017/p/12901123.html

 

正文

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

本文会罗列一些NIO和IO的不同点,和用法,以及它们都是如何影响设计的。

主要的不同点

IO NIO
面向流 面向缓冲区
阻塞IO 非阻塞IO
无选择器 有选择器

面向流 VS 面向缓冲区

面向流,意味着你将从一个流中有序地读取字节数据,你无法在流中前后移动操作位置。如果你想这么做,你必须把流全部读取出来,然后存储到一个buffer里面,继而前后移动操作位置。

面向缓冲区就不同了,你可以在buffer上移动操作的位置。但是,面向缓冲区意味着你需要去判断哪些数据能够形成一套完整的信息。以及,你要确保新进入的数据不会覆盖了旧数据。

阻塞 VS 非阻塞

阻塞意味着当一个线程调用了read或者write,这个线程就不能做其它事情,必须等待io两阶段都结束。

非阻塞就不同了,一个线程可以控制多个IO,当IO可用的时候线程再进行处理。线程可以做其它事情。

选择器

选择器是NIO独有的,选择器可以监控多个channel,使得单线程可以控制多个IO的输入输出。

NIO和IO如何影响程序设计

无论你选择哪种方式,将会影响以下三个方面

1.调用NIO或者IO的API类

2.数据的处理过程

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

API调用

NIO和IO的API调用当然是不同的,这点毋庸置疑。

数据处理

在IO中,你将从流里面读取数据,例如你将逐行读取

Name: Anna
Age: 25
Email: anna@mailserver.com
Phone: 1234567890

这个文本流在IO下可以这样处理

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();

readLine方法返回的就会是一行数据,在此之前会阻塞等待,线程也不能做别的事,如图

 

 如果是NIO的实现

ByteBuffer buffer = ByteBuffer.allocate(48);

int bytesRead = inChannel.read(buffer);

read方法会立即返回,bytesRead可能为0,也可能大于0。也就是说数据可能不会一次性读完,所以你需要循环调用

ByteBuffer buffer = ByteBuffer.allocate(48);

int bytesRead = inChannel.read(buffer);

while(! bufferFull(bytesRead) ) {
    bytesRead = inChannel.read(buffer);
}

bufferFull方法校验是否构成了一个完整的数据信息,流程如图

 

 汇总

NIO使得你可以单线程管理多个channel,但是也导致数据解析的复杂度上升。

如果你需要并发很多连接,每个连接传输的数据量较小,例如聊天室程序,使用NIO是非常正确的。一个线程管理多个连接如图

 

 如果连接非常少,但是传输的数据非常大,那么采用传统IO比较合适,如图

 

posted @ 2020-05-20 10:12  __lay  阅读(192)  评论(0编辑  收藏  举报