Java IO与NIO 学习

简介:

面向流与面向缓冲

  Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO面向流意味着每次从流中读一个或多个字节,直至读取所有字节,它们没有被缓存在任何地方。此外,它不能前后移动流中的数据。如果需要前后移动从流中读取的数据,需要先将它缓存到一个缓冲区。 Java NIO的缓冲导向方法略有不同。数据读取到一个它稍后处理的缓冲区,需要时可在缓冲区中前后移动。这就增加了处理过程中的灵活性。但是,还需要检查是否该缓冲区中包含所有您需要处理的数据。而且,需确保当更多的数据读入缓冲区时,不要覆盖缓冲区里尚未处理的数据。


  阻塞与非阻塞IO

  Java IO的各种流是阻塞的。这意味着,当一个线程调用read() 或 write()时,该线程被阻塞,直到有一些数据被读取,或数据完全写入。该线程在此期间不能再干任何事情了。 Java NIO的非阻塞模式,使一个线程从某通道发送请求读取数据,但是它仅能得到目前可用的数据,如果目前没有数据可用时,就什么都不会获取。而不是保持线程阻塞,所以直至数据变的可以读取之前,该线程可以继续做其他的事情。 非阻塞写也是如此。一个线程请求写入一些数据到某通道,但不需要等待它完全写入,这个线程同时可以去做别的事情。 线程通常将非阻塞IO的空闲时间用于在其它通道上执行IO操作,所以一个单独的线程现在可以管理多个输入和输出通道(channel)。


  选择器(Selectors)

  Java NIO的选择器允许一个单独的线程来监视多个输入通道,你可以注册多个通道使用一个选择器,然后使用一个单独的线程来“选择”通道:这些通道里已经有可以处理的输入,或者选择已准备写入的通道。这种选择机制,使得一个单独的线程很容易来管理多个通道。


  NIO和IO如何影响应用程序的设计

  无论您选择IO或NIO工具箱,可能会影响您应用程序设计的以下几个方面:

  对NIO或IO类的API调用。

  数据处理。

  用来处理数据的线程数。

java.NIO包里包括三个基本的组件

l buffer:因为NIO是基于缓冲的,所以buffer是最底层的必要类,这也是IO和NIO的根本不同,虽然stream等有buffer开头的扩展类,但只是流的包装类,还是从流读到缓冲区,而NIO却是直接读到buffer中进行操作。

因为读取的都是字节,所以在操作文字时,要用charset类进行编解码操作。

l channel:类似于IO的stream,但是不同的是除了FileChannel,其他的channel都能以非阻塞状态运行。FileChannel执行的是文件的操作,可以直接DMA操作内存而不依赖于CPU。其他比如socketchannel就可以在数据准备好时才进行调用。

l selector:用于分发请求到不同的channel,这样才能确保channel不处于阻塞状态就可以收发消息。

与传统IO的优势

在老的IO包中,serverSocket和socket都是阻塞式的,因此一旦有大规模的并发行为,而每一个访问都会开启一个新线程。这时会有大规模的线程上下文切换操作(因为都在等待,所以资源全都被已有的线程吃掉了),这时无论是等待的线程还是正在处理的线程,响应率都会下降,并且会影响新的线程。


而NIO包中的serverSocket和socket就不是这样,只要注册到一个selector中,当有数据放入通道的时候,selector就会得知哪些channel就绪,这时就可以做响应的处理,这样服务端只有一个线程就可以处理大部分情况(当然有些持续性操作,比如上传下载一个大文件,用NIO的方式不会比IO好)。

通过两个图的比较,可以看出IO是直连的,每个请求都给一条线程来处理,但是NIO却是基于反应堆(selector)来处理,直到读写的数据准备好后,才会通知相应的线程来进行处理。一言以蔽之:“selector不会让channel白占资源,没事的时候给我去睡觉。”

PS:NIO基于字节进行传输,在IO时要注意decode/encode。












本文转自里冲51CTO博客,原文链接: http://blog.51cto.com/coollast/1106350  ,如需转载请自行联系原作者



相关文章
|
1天前
|
存储 Java
Java IO流:深入解析与技术应用
Java IO流:深入解析与技术应用
|
2天前
|
存储 Java 编译器
Java文件IO操作基础
Java文件IO操作基础
5 0
|
2天前
|
Oracle NoSQL 关系型数据库
实时计算 Flink版操作报错之报错:java.lang.ClassNotFoundException: io.debezium.connector.common.RelationalBaseSourceConnector,如何解决
在使用实时计算Flink版过程中,可能会遇到各种错误,了解这些错误的原因及解决方法对于高效排错至关重要。针对具体问题,查看Flink的日志是关键,它们通常会提供更详细的错误信息和堆栈跟踪,有助于定位问题。此外,Flink社区文档和官方论坛也是寻求帮助的好去处。以下是一些常见的操作报错及其可能的原因与解决策略。
|
3天前
|
Java
【JAVA学习之路 | 进阶篇】Record(记录)与密封类(sealed)
【JAVA学习之路 | 进阶篇】Record(记录)与密封类(sealed)
|
3天前
|
Java
【JAVA学习之路 | 进阶篇】方法引用与构造器引用
【JAVA学习之路 | 进阶篇】方法引用与构造器引用
|
3天前
|
Java 编译器
【JAVA学习之路 | 进阶篇】Lambda表达式
【JAVA学习之路 | 进阶篇】Lambda表达式
|
3天前
|
存储 Java API
【JAVA学习之路 | 进阶篇】(处理流)转换流与对象流
【JAVA学习之路 | 进阶篇】(处理流)转换流与对象流
|
3天前
|
缓存 Java
【JAVA学习之路 | 进阶篇】节点流与缓冲流(处理流之一)
【JAVA学习之路 | 进阶篇】节点流与缓冲流(处理流之一)
|
3天前
|
存储 Java API
【JAVA学习之路 | 进阶篇】IO流及流的分类
【JAVA学习之路 | 进阶篇】IO流及流的分类
|
3天前
|
Java 测试技术 C++
【JAVA学习之路 | 进阶篇】File类及常用方法
【JAVA学习之路 | 进阶篇】File类及常用方法