`

翻译-【Java NIO学习系列】Java NIO与IO

 
阅读更多

  翻译:http://tutorials.jenkov.com/java-nio/nio-vs-io.html

     当研究学习java NIO与标准IO的API时,一个问题马上涌入脑海:我应该什么时候使用NIO,什么时候使用IO,

     本文中我将阐述Java NIO和标准IO之间的差异,它们的使用场景,及它们在您代码设计中的影响。

     java NIO与IO的主要差异

     下表将总述java NIO与IO的差异,我讲在表格后面详细讲述各个部分的差异。

Java  标准IO Java NIO
面向流(Stream oriented 面向缓冲区(Buffer oriented
阻塞IO(Blocking IO 非阻塞IO(Non blocking IO
  选择器(Selectors

       面向流(Stream oriented)VS 面向缓冲区(Buffer oriented

       Java NIO与标准IO第一个最大的区别是:标准IO是面向流,NIO是面向缓冲区 。这是什么意思呢?

       Jave 标准IO面向流表示你可以在一个时间点里从流中读取一个或多个字节(bytes),你使用或处理完毕这些已经读取的字节后,它们也不会缓存在任何地方,此外你也不能前移后移在流中的数据,如果你要前移或后移在流中的数据,你应该将数据缓存在缓冲区(buffer)。

      Java NIO面向缓冲区方式稍有区别,将要被处理的数据被读入到缓冲区,在缓冲区里你可以按照你自己的需要前移或后移。这将给你在处理时带来极大的灵活性,但是为了成功的处理这些数据,你必须校验缓冲区是否包含你全部所需要的数据。同时你也的确认当读取更多的数据时,已经处理过的数据不会再次被读到缓冲区。

       阻塞IO(Blocking IO)VS非阻塞IO(Non blocking IO

      Java标准IO的各种流是阻塞的,这意味着当一个线程调用read() or write()时,线程将会被阻塞,直到一些数据被读取或者数据被完全写入的时,在此期间线程不能做任何其他事情。

     Java NIO的非阻塞方式可以使线程从通道(channel)里面读取数据,且只读取可用数据,如果当前没有可用数据,什么也不获取。此时并不将线程阻塞,直到数据变的可以读取期间,线程也可以做其他事情。

    非阻塞式写(non-blocking writing)同样适用。线程线程可以将数据写入通道,不需要等待完全写入,线程可以继续执行并执行其他操作。

     在非阻塞IO执行时,线程将空闲时间花费在同时执行的其他通道的IO上。这意味着,单个的线程可以管理多个通道的输入和输出。

     选择器(Selectors

     Java NIO选择器(Selectors)允许单个线程监控多个通道的输入和输出。你可以将多个通道注册在一个选择器(Selectors),然后使用该线程“选择”已经输入准备好处理的通道,或已经准备写入的通道。选择器机制使得单个线程方便的管理多个通道。

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

       无论你使用IO或者NIO作为你的工具箱,将会影响到你程序的一下几个方面:

      1.NIO或IO类的API调用

      2.数据处理

     3.数据处理的线程数

     API 调用

     当然使用NIO的API调用与IO的API调用看起来就存在差异,这并不奇怪,NIO不仅仅从流中(例如 InputStream【输入流】逐个字节的读取数据,且将数据先读取到缓冲区中再处理。

      数据处理

      使用纯粹的NIO或IO设计同样影响到数据的处理。

      在IO设计中从InputStream【输入流】或Reader 中逐个字节的读取数据, 想像你真在处理一个基于文本行的数据流。实例如下:

 

Name: Anna
Age: 25
Email: anna@mailserver.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()方法返回,你就可以确定一行完整的文本已经被读取。reader.readLine()将阻塞直到完整行读取完毕,这也是你为什么直到第一个包含的是name。类似,第二个reader.readLine()调用返回,你也直到该行包含的是age。

     正如你所见,该程序进行时,才会有新的数据读取,每一步,你知道这些数据是什么。一旦线程已经执行过某些数据,线程是不会的回退这些数据(大部分是不可以)。下图也说明了这条原则:

Java IO: Reading data from a blocking stream.

     NIO的实现有所不同,一下是简单的例子

 

ByteBuffer buffer = ByteBuffer.allocate(48);

int bytesRead = inChannel.read(buffer);

    注意的是从通道读取字节到字节缓冲区(ByteBuffer)的第二行。当该方法调用返回时,你也是不知道是否你所需要的数据是否在缓冲区(Buffer)中。你仅仅知道的事,缓冲区(Buffer)包含了些数据。这样让程序处理变得有些困难。

      如果在第一调用read(buffer)后,只有半行的数据被读入到缓冲区(Buffer)例如: "Name: An" ,你能处理这样的数据?显然不能,你必须等到至少一个完整行数据被读入到缓冲区,这样数据处理才有意义。

     你怎么能才能知道缓冲区里面已经完全包含了你所要处理的数据呢?好吧,你不能,唯一的方式检查缓冲区里的数据。这样导致的结果在所有数据数据在缓冲区里前,你必须检查几次在缓冲区里的数据。这不仅效率低下,而且可以使程序设计方案混乱不堪。例如:

ByteBuffer buffer = ByteBuffer.allocate(48);

int bytesRead = inChannel.read(buffer);

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

    bufferFull()方法必须跟踪多少数据被读入到缓冲区中,返回truefalse依赖的是缓冲区是否已经写满。

换句话说,一旦缓存区将被处理,可以认为缓冲区已经被写满。

    bufferFull()方法扫描缓冲区,必须保持在调用bufferFull()方法前后调用bufferFull()后一致的状态。如果不是,下个读入的数据将没有写入到正确的位置。这是不可能的,但它的另一个问题的引起注意。

     缓冲区满了,它能被处理。如果它没有满,在个别的案例中,你或许可以处理部分的数据。

     下图 说明 is-data-in-buffer-ready 循环:

     

     总结

     NIO允许你使用一个(或多个)线程管理多个通道(network connections or files),解析数据的成功代价比从阻塞的流中读取数据的更大,更复杂。

     如果你要管理同时存在的数以千计的的连接,且只发送少量数据,例如:聊天服务,服务端NIO是一个最佳方案。同样,如果你要维持大量与其他计算机的连接,e.g P2P网络,使用单个线程管理外建的连接是个优势。单线程,多连接设计图示如下:
 

如果你只有少许连接,并且有高带宽,在一个时间端内发送大量数据,或许标准IO是最佳方案。传统的IO设计图如下:

后面还有几篇文章,也正在翻译、、、、

  • 大小: 9.8 KB
  • 大小: 11.2 KB
  • 大小: 8.9 KB
  • 大小: 17.1 KB
分享到:
评论

相关推荐

    Java语言基础教程-Java NIO流篇2

    Java NIO(New IO)是Java 1.4版本引入的一个新模块,是对传统IO模型的补充和扩展。本教程将深入讲解Java NIO中的流和通道概念,以帮助开发者更好地理解和利用这一强大的功能。 首先,我们要理解Java NIO的核心组件...

    java io 与java nio区别

    ### Java IO 与 Java NIO 的区别 在深入探讨Java IO与Java NIO之间的区别之前,我们先简单回顾一下这两种I/O模型的基本概念。 #### 1. Java IO(Blocking IO) Java IO,也称为传统的阻塞式IO或同步阻塞式IO,是...

    JavaNIO chm帮助文档

    Java NIO系列教程(一) Java NIO 概述 Java NIO系列教程(二) Channel Java NIO系列教程(三) Buffer Java NIO系列教程(四) Scatter/Gather Java NIO系列教程(五) 通道...Java NIO系列教程(十二) Java NIO与IO

    2021最新-Java NIO视频教程.txt打包整理.zip

    在"2021最新-Java NIO视频教程.txt打包整理.zip"这个资源中,你可能学习到如何创建和管理通道、缓冲区的使用、选择器的注册与选择、文件系统操作的优化、字符集编码的处理以及如何利用NIO进行网络编程等内容。...

    Java语言基础教程-Java NIO流篇3

    Java NIO(New IO)是Java 1.4版本引入的一个新特性,是对传统IO模型的补充和扩展,提供了一种更高效的数据处理方式。在本教程中,我们将深入探讨Java NIO流的两个关键部分:文件通道操作和选择器。 ### 文件通道...

    JAVA-NIO-DEMO

    Java NIO(New IO)是Java 1.4版本引入的一个新模块,它提供了一种不同于传统IO(基于字节流和字符流)的I/O操作方式。传统的IO模型是阻塞式的,而NIO的核心特点是非阻塞,这使得在处理大量并发I/O请求时更为高效。...

    Java NIO与IO性能对比分析.pdf

    本文将分析Java NIO与Java IO在性能上的对比,并尝试找出性能差异的原因,以及探讨哪种编程模型更适合高并发的应用场景。 Java IO模型是一种阻塞型I/O模型,在数据的读写过程中,如果线程在等待数据,将会一直被挂...

    Java-NIO-Netty框架学习

    Java NIO (Non-blocking Input/Output) 是Java平台中用于高效处理I/O操作的一种机制,它与传统的IO模型( Blocking I/O)相比,提供了更高级别的抽象,允许应用程序以非阻塞的方式读写数据,提高了并发性能。...

    Java IO与NIO文档

    Java IO与NIO是Java平台中用于处理输入输出操作的核心技术。它们在处理数据传输、文件操作、网络通信等方面起着至关重要的作用。本篇将深入探讨这两个领域,旨在帮助开发者更好地理解和应用这些概念。 首先,Java ...

    java nio与io性能测试

    本文将深入探讨Java NIO与IO的性能测试,并通过代码实例来展示它们之间的差异。 首先,我们来看传统的Java IO模型。IO模型基于流,数据是从输入流到输出流的单向传输。例如,`FileInputStream`和`FileOutputStream`...

    Java IO_NIO

    Java IO(Input/Output)是Java编程语言中用于处理输入输出操作的基础框架,它提供了丰富的类库,使得程序能够与各种设备、文件、...理解和掌握Java IO与NIO的使用,对于提升Java应用程序的性能和可扩展性至关重要。

    Ioserver java Nio socket 框架

    Ioserver java Nio socket 框架 是个不错的NIO 通讯框架,本来想学习mina框架,看了看mina的源码太头痛,本人觉得看懂了Ioserver 再看mina的框架,想多的学习 java NIO 的也可以下载 看看,很值得学习啊!!!

    JAVA IO and NIO

    Java IO (Input/Output) 和 NIO (Non-blocking Input/Output) 是Java平台中用于处理输入和输出操作的重要部分。这两种技术在实现客户端与服务器之间的通信时起着至关重要的作用。下面将详细介绍Java IO和NIO的特点、...

    JAVA IO-NIO 详解

    ### JAVA IO-NIO 详解 #### 一、IO与NIO概述 在Java开发中,输入/输出(IO)操作是程序与外部环境交互的重要环节。通过IO操作,程序可以读取外部数据或向外部环境输出数据。Java的IO体系自Java 1.0以来就一直存在...

    Netty--Java IO/NIO 框架 简单学习例子

    本篇文章将简单介绍 Netty 以及其与 Java IO 和 NIO 的关系。 首先,Java IO(Input/Output)是Java标准库提供的基本输入输出操作。IO 流模型基于阻塞IO,即当数据不可读或写入时,程序会暂停等待。这种方式在处理...

    Java-NIO-系列教程

    通过以上介绍,我们可以了解到 Java NIO 提供了一系列强大而灵活的 API 来处理 I/O 操作,相比于传统的 Java IO,它在性能和灵活性方面都有显著提升。后续章节将深入探讨这些核心组件的具体使用方法和高级特性。

Global site tag (gtag.js) - Google Analytics