第十一节 netty前传-NIO 和IO对比
2018-11-01 本文已影响2人
勃列日涅夫
NIO和IO的区别
两者有两点最明显也是最主要的区别
IO:面向流、阻塞模式
NIO:面向缓冲、非阻塞模式
- 对于第一点
第一个重要区别是IO是面向流的,NIO是面向缓冲区的。
面向流的Java IO意味着可以从流中一次读取一个或多个字节。 至于用读取字节做什么取决于客户。 它们不会缓存在任何地方。 此外,你无法在流中的数据中前后移动。 如果需要在从流中读取的数据中前后移动,则需要先将其缓存在缓冲区中。
Java NIO的面向缓冲区的方法略有不同。 将数据读入缓冲区,稍后处理该缓冲区。 客户可以根据需要在缓冲区中前后移动。 这使得在处理过程中更具灵活性。 但是,还需要检查缓冲区是否包含完整处理所需的所有数据。 并且,需要确保在将更多数据读入缓冲区时,不要覆盖尚未处理的缓冲区中的数据。
- 对于第二点
第二个区别其实和和第一个也有很大关系。java io面向流,这就使得在从流中读写数据都是阻塞进行,而Java NIO一方面通过Selectors选择器允许单个线程监视多个输入通道。 也可以使用选择器注册多个通道,然后使用单个线程“select”已经准备好的通道。 这种选择器机制使单个线程可以轻松管理多个通道,另一方面面向缓冲使得java nio的读写可以立刻返回(非阻塞)。
相较而言java nio比java io更高效,但同时使用也更为复杂,比如下面例子
我的F:\book下有个a.txt内容如下
aaa
bbb
ccc
- 在使用java io模式读取时
File file=new File("F:\\book\\a.text");
//获取输入流
InputStream input = new FileInputStream(file);
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
//逐行读取
String a = reader.readLine();
String b = reader.readLine();
String c = reader.readLine();
- 注意上面得io读取,因为时阻塞,所以一旦reader.readLine()方法返回,就确定已经读取了这一行得文本,如果nio中,非阻塞读取结果可能,下面java nio的实现方式
ByteBuffer buffer = ByteBuffer.allocate(48);
int bytesRead = inChannel.read(buffer);
- 注意: 在第二行从channel读取字节到ByteBuffer。 当该方法调用返回时,我们并不知道所需的所有数据是否都在缓冲区内。 只知道缓冲区包含一些字节。 所以这种情况下设计nio模式的就会比较复杂,借用之前的部分代码片段如下:
ByteBuffer buffer = ByteBuffer.allocate(48);
//注意:这个方法会记录读取的位置,所以后续读取不会从头开始读取
int bytesRead = fileChannel.read(buffer);
System.out.println(bytesRead);
//读取到数据
while(bytesRead != -1)
{
//反转后为可以读取缓冲中的数据
buf.flip();
while(buf.hasRemaining())//position < limit;表示可读
{
//读取
System.out.print((char)buf.get());
}
//没有可读数据后,清除已读数据,从未读数据之后开始写入
buf.compact();
//开始继续读取
bytesRead = fileChannel.read(buf);
}
上面的代码也可简化入下图:
图片.png
也是由于nio的非阻塞和选择器这种特点,可以使得一个单线程管理多个通道,同时还可以让每一个通道使用单独的线程处理业务逻辑
简化如下: