Java 输入输出 IO NIO AIO三兄弟对比分析对比分析

目录
  • 1、Java I/O发展史
  • 2、Java IO
    • 2.1 简介
    • 2.2 基础概念
      • 2.2.1 输入流和输出流
      • 2.2.2 字节流和字符流
      • 2.2.3 缓冲流
    • 2.3 Java IO的使用
      • 2.3.1 文件读写
  • 3、Java NIO
    • 3.1 简介
    • 3.2 核心概念
      • 3.2.1 选择器(Selector)
      • 3.2.2 通道(Channel)
      • 3.2.3 缓冲区(Buffer)
    • 3.3 Java NIO的使用
      • 3.3.1 缓冲区操作
      • 3.3.2 通道操作
  • 4、Java AIO
    • 4.1 Java AIO的原理
    • 4.2 Java AIO的特点
    • 4.3 Java AIO的应用
    • 总结
  • 5、相关面试题

1、Java I/O发展史

Java IO(Input/Output)是Java语言中用于读写数据的API,它提供了一系列类和接口,用于读取和写入各种类型的数据。下面是Java IO发展史的简要介绍:

  • JDK 1.0(1996年) 最初的Java IO只支持字节流(InputStream、OutputStream)和字符流(Reader、Writer)两种,基于阻塞式IO(BIO)模型。
  • JDK 1.1(1997年) JDK 1.1引入了NIO(New IO)包,支持了缓存区(Buffer)、通道(Channel)等概念,提供了更高效的IO操作方式,可以实现非阻塞式IO(NIO)模式。
  • JDK 1.4(2002年) JDK 1.4增加了NIO.2 API,也称为Java NIO with buffers,提供了更   强大的文件处理功能和更高效的IO操作。
  • JDK 7(2011年) JDK 7引入了NIO.2的改进版——NIO.2 with Completion Ports,也称为AIO(Asynchronous IO),支持异步IO方式,在处理大量并发请求时具有优势。

以下是三者之间的区别:

  • 阻塞IO(BIO) BIO是Java最初的IO模型,它采用阻塞方式进行数据读写操作。即当一个线程在执行IO操作时,若没有数据可读,则该线程会一直阻塞等待,直到有数据可读或者超时。BIO适合处理连接数比较小且固定的场景,但并发能力不足。
  • 非阻塞IO(NIO) NIO是Java 1.4引入的新的IO模型,它采用了多路复用器(Selector)机制,通过少量线程同时管理多个通道,实现了单线程同时处理多个请求的效果。NIO具有高并发性、高吞吐量和更高的可靠性,适合处理连接数多且连接时间较短的场景。
  • 异步IO(AIO) AIO是Java 1.7开始支持的IO模型,它采用事件驱动的方式进行数据读写操作,当数据准备好后,在回调函数中进行处理。与NIO不同,AIO的读写操作是异步的,不需要通过轮询方式去检查数据是否准备好。AIO适合处理连接数多、连接时间长且有较多读写操作的场景。

2、Java IO

2.1 简介

在Java编程中,IO(Input/Output)操作是非常常见的操作,它涉及到文件读写、网络通信等方面。Java提供了各种类来支持这些操作。本文将从IO的基础知识讲起,逐步深入,介绍Java IO的各个方面。

2.2 基础概念

2.2.1 输入流和输出流

在Java中,输入流(InputStream)和输出流(OutputStream)是两个重要的抽象类。输入流表示输入数据的来源,可以是文件、网络连接、管道等;输出流表示输出数据的去向,可以是文件、网络连接、管道等。输入流和输出流的使用方式是相似的,都是通过创建流对象,然后使用相应的方法接口进行读写操作。

2.2.2 字节流和字符流

Java中的IO操作还可以分为字节流和字符流两种。字节流以字节(byte)为单位进行操作,适用于处理二进制数据,例如图像、音频等;而字符流以字符(char)为单位进行操作,适用于处理文本数据,例如文本文件等。Java中,字节流主要由InputStream和OutputStream类以及其子类实现,而字符流主要由Reader和Writer类以及其子类实现。

2.2.3 缓冲流

在进行IO操作时,我们可能需要经常进行读写操作,而频繁的读写可能会导致性能问题。为了解决这个问题,Java提供了缓冲流(Buffered Stream)来提高IO操作的效率。缓冲流可以通过内部缓存区域来减少对底层资源的访问次数,从而提高数据读写的效率。

2.3 Java IO的使用

2.3.1 文件读写

Java中的文件读写是开发中最常见的操作之一。下面是一个读取文件内容并输出的示例:

    try (FileInputStream fis = new FileInputStream("test.txt");
         InputStreamReader isr = new InputStreamReader(fis);
         BufferedReader br = new BufferedReader(isr)) {
        String line;
        while ((line = br.readLine()) != null) {
            System.out.println(line);
        }
    } catch (IOException e) {
        e.printStackTrace();
    }

在这个示例中,我们使用了FileInputStream、InputStreamReader和BufferedReader等类来完成文件的读取。首先,我们通过FileInputStream类创建了一个输入流对象,并指定了要读取的文件名称;然后通过InputStreamReader将字节流转换为字符流,再通过BufferedReader实现按行读取文本内容。

类似地,在Java中进行文件写操作也非常简单,下面是一个写入文件的示例:

try (FileOutputStream fos = new FileOutputStream("test.txt");
     OutputStreamWriter osw = new OutputStreamWriter(fos);
     BufferedWriter bw = new BufferedWriter(osw)) {
    bw.write("Hello, world!");
} catch (IOException e) {
    e.printStackTrace();
}

在这个示例中,我们使用了FileOutputStream、OutputStreamWriter和BufferedWriter等类来完成文件的写入。首先,我们通过FileOutputStream类创建了一个输出流对象,并指定了要写入的文件名称;然后通过OutputStreamWriter将字节流转换为字符流,再通过BufferedWriter实现按行写入文本内容。

3、Java NIO

3.1 简介

Java NIO(New IO)是Java SE 1.4引入的一个新的IO API,它提供了比传统IO更高效、更灵活的IO操作。与传统IO相比,Java NIO的优势在于它支持非阻塞IO和选择器(Selector)等特性,能够更好地支持高并发、高吞吐量的应用场景。本文将从NIO的基础知识讲起,逐步深入,介绍Java NIO的各个方面。

3.2 核心概念

3.2.1 选择器(Selector)

选择器是Java NIO中的一个重要组件,它可以用于同时监控多个通道的读写事件,并在有事件发生时立即做出响应。选择器可以实现单线程监听多个通道的效果,从而提高系统吞吐量和运行效率。

3.2.2 通道(Channel)

通道是一个用于读写数据的对象,类似于Java IO中的流(Stream)。与流不同的是,通道可以进行非阻塞式的读写操作,并且可以同时进行读写操作。通道分为两种类型:FileChannel和SocketChannel,分别用于文件和网络

通信。

3.2.3 缓冲区(Buffer)

在Java NIO中,所有数据都是通过缓冲区对象进行传输的。缓冲区是一段连续的内存块,可以保存需要读写的数据。缓冲区对象包含了一些状态变量,例如容量(capacity)、限制(limit)、位置(position)等,用于控制数据的读写。

3.3 Java NIO的使用

3.3.1 缓冲区操作

Java NIO中的缓冲区操作主要包括数据读取和数据写入两种操作。下面是一个简单的缓冲区读取示例:

ByteBuffer buffer = ByteBuffer.allocate(1024);
try (FileChannel channel = new FileInputStream("test.txt").getChannel()) {
    int bytesRead = channel.read(buffer);
    while (bytesRead != -1) {
        buffer.flip();
        while (buffer.hasRemaining()) {
            System.out.print((char) buffer.get());
        }
        buffer.clear();
        bytesRead = channel.read(buffer);
    }
} catch (IOException e) {
    e.printStackTrace();
}

在这个示例中,我们使用了FileChannel类和ByteBuffer类来完成文件的读取。首先,我们通过FileInputStream类创建了一个输入流对象,然后通过getChannel()方法获取到对应的通道对象;接着,我们创建了一个容量为1024字节的ByteBuffer对象,并调用read()方法从通道中读取数据,将读取到的数据保存在缓冲区中。读取完成后,我们通过flip()方法将缓冲区切换为读模式,并使用hasRemaining()和get()方法逐个读取数据;最后通过clear()方法清空缓冲区,准备进行下一轮读取。

Java NIO中的缓冲区写操作也非常类似,下面是一个简单的缓冲区写入示例:

ByteBuffer buffer = ByteBuffer.wrap("Hello, world!".getBytes());
try (FileChannel channel = new FileOutputStream("test.txt").getChannel()) {
    channel.write(buffer);
} catch (IOException e) {
    e.printStackTrace();
}

在这个示例中,我们使用了FileChannel类和ByteBuffer类来完成文件的写入。首先,我们通过ByteBuffer.wrap()方法将字符串转换为ByteBuffer对象;然后,我们通过FileOutputStream类创建了一个输出流对象,再通过getChannel()方法获取到对应的通道对象;接着,我们调用write()方法将缓冲区中的数据写入通道中,完成文件写入操作。

3.3.2 通道操作

Java NIO中的通道(Channel)是用于进行数据传输的对象。通道可以连接到源或目标节点,用于读取和写入数据。与传统的Java IO不同,NIO中的通道可以实现非阻塞式地读写数据,从而提高了应用程序的性能和并发处理能力。

要使用通道进行读写操作,首先需要打开通道。Java NIO中有多种类型的通道,每种通道都提供了自己的打开方式。例如,要打开一个文件通道,可以通过FileInputStream或FileOutputStream对象获取对应的FileChannel对象,如下所示:

    FileChannel channel = new FileInputStream("file.txt").getChannel();

读取数据 一旦打开了通道,就可以开始读取数据。在NIO中,数据通过缓冲区进行传输。要读取数据,需要将数据存储在缓冲区中,然后从缓冲区中读取数据。以下是一个简单的读取操作示例:

ByteBuffer buffer = ByteBuffer.allocate(1024);
// 从通道中读取数据
int bytesRead = channel.read(buffer);
while (bytesRead != -1) {
    // 切换为读模式
    buffer.flip();
    // 读取缓冲区中的数据
    while (buffer.hasRemaining()) {
        System.out.print((char) buffer.get());
    }
    // 清空缓冲区
    buffer.clear();
    bytesRead = channel.read(buffer);
}

在这个示例中,我们首先创建了一个容量为1024字节的ByteBuffer对象,并使用channel.read()方法从文件通道中读取数据。读取到数据后,我们将ByteBuffer切换为读模式,再使用hasRemaining()和get()方法逐个读取缓冲区中的数据。

写入数据 要写入数据,也需要将数据存储在缓冲区中,然后将缓冲区中的数据写入到通道中。以下是一个简单的写入操作示例:

ByteBuffer buffer = ByteBuffer.wrap("Hello, world!".getBytes());
// 将数据写入通道
channel.write(buffer);

在这个示例中,我们首先使用ByteBuffer.wrap()方法将字符串转换为ByteBuffer对象,在通过channel.write()方法将ByteBuffer中的数据写入到通道中。

4、Java AIO

Java AIO(Asynchronous IO)是一种基于事件和回调的IO模型,相比Java BIO(Blocking IO)和Java NIO(Non-blocking IO),它具有更高的并发性、更高的吞吐量和更高的可靠性。本文将介绍Java AIO的原理、特点和应用。

4.1 Java AIO的原理

Java AIO采用异步IO方式进行数据读写操作,与Java NIO不同,它不需要通过轮询方式去检查数据是否准备好,而是由操作系统完成。当数据准备好后,操作系统会通知应用程序,并在回调函数中进行处理。

AIO使用了三个核心组件:AsynchronousChannel、CompletionHandler和
AsynchronousServerSocketChannel。其中,AsynchronousChannel是读/写数据的通道,CompletionHandler是I/O操作完成时的回调方法,AsynchronousServerSocketChannel是异步服务器端套接字通道,用于监听客户端的连接请求。

当数据准备好后,操作系统将通知应用程序,并在回调函数中执行I/O操作完成时的回调方法。这样就避免了线程阻塞等待I/O操作完成的情况,从而提高了程序的效率和并发处理能力。

4.2 Java AIO的特点

  • 高并发性:Java AIO采用异步IO方式进行数据读写操作,可以实现高并发处理能力。
  • 高吞吐量:Java AIO支持异步读写操作,可以同时处理多个请求,从而提高了数据读写的效率和吞吐量。
  • 高可靠性:由于Java AIO采用异步IO方式进行数据读写操作,可以避免线程阻塞等待I/O操作完成的情况,从而提高程序的可靠性。
  • 简单易用:Java AIO提供了简单易用的API,不需要编写复杂的代码就可以实现异步IO操作。

4.3 Java AIO的应用

Java AIO适用于需要大量并发连接,但每个连接却很少有数据交互的场景,例如基于消息的应用程序、远程过程调用(RPC)等。在这些应用场景中,AIO可以大幅度提高程序的性能和并发处理能力,从而满足用户对高吞吐量和低延迟的要求。

另外,Java AIO也可以用于开发高性能的网络服务器,例如聊天室服务器、在线游戏服务器等。由于AIO支持异步读取输入流和输出流,因此可以同时处理多个客户端请求,有效地提高了服务器的并发处理能力。

总结

Java AIO作为一种高性能、高并发的IO模型,具备很多优点,但也存在着一些缺点,如对小负载的连接,AIO的开销可能会导致性能下降。因此,在实际应用中,需要权衡各种因素,根据实际需求进行评估和选择。

5、相关面试题

1、什么是Java IO和NIO?

Java IO(Input/Output)是Java中传统的输入输出操作,使用字节流和字符流进行数据传输。
Java NIO(New Input/Output)是Java 1.4引入的新的输入输出API,它更加高效地处理数据。

2、什么是阻塞和非阻塞IO?

阻塞IO(Blocking IO)在进行IO操作时会一直等待,直到IO完成,期间无法进行其他操作。
非阻塞IO(Non-blocking IO)在进行IO操作时不会一直等待,而是立即返回结果,如果IO还没有完全完成,则可以继续做其他事情。

3、什么是缓冲区?有哪些类型的缓冲区?

缓冲区是一个用于存储数据的数组,在进行IO操作时需要通过缓冲区来进行读写数据。
Java的缓冲区分为字节缓冲区(ByteBuffer、CharBuffer、ShortBuffer等)和直接缓冲区(DirectByteBuffer、DirectCharBuffer、DirectShortBuffer等)。

4、什么是通道(Channel)?

通道是NIO中用于进行数据传输的对象,它可以连接到源或目标节点,用于读取和写入数据。

5、什么是选择器(Selector)?

选择器是NIO中的一个对象,它可以通过轮询注册在其上的通道来检查它们是否有事件发生(如可读、可写等),从而避免了阻塞式IO中需要等待IO完成的问题。

6、Java IO和NIO之间有什么区别?

Java IO基于流的方式进行数据传输,而NIO基于缓冲区和通道进行数据传输。
Java IO是阻塞式的,而NIO可以采用阻塞或非阻塞模式。
Java IO对线程使用较多,每个IO操作都需要创建一个线程,而NIO可以使用单个线程处理多个IO操作。

7、什么是文件通道(FileChannel)?

文件通道是NIO中用于读取和写入文件的通道,它支持随机访问和内存映射文件等高级功能。

8、Java IO和NIO哪个更快?

在大量小数据量的情况下,Java IO可能更快,因为它可以通过缓冲区一次性读取所有数据。
在大量大块数据的情况下,NIO可能更快,因为它可以使用零拷贝技术直接将数据从磁盘读入内存,减少了数据复制的开销。

以上就是Java 输入输出 IO NIO AIO三兄弟对比分析对比分析的详细内容,更多关于Java 输入输出IO NIO AIO的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java框架解说之BIO NIO AIO不同IO模型演进之路

    目录 引言 IO模型 1.什么是IO 2.应用程序IO交互 (1)计算机资源统一管理 (2)底层硬件调用统一封装 3.5种IO模型 (1)阻塞型IO (2)非阻塞型IO (3)多路复用IO (4)信号驱动IO (5)异步IO Java中的IO模型 BIO NIO AIO 总结 引言 Netty作为高性能的网络通信框架,它是IO模型演变过程中的产物.Netty以Java NIO为基础,是一种基于异步事件驱动的网络通信应用框架,Netty用以快速开发高性能.高可靠的网络服务器和客户端程序,很多开源框

  • Java中BIO、NIO和AIO的区别、原理与用法

    目录 IO BIO NIO AIO 区别及联系 各自适用场景 使用方式 IO 什么是IO? 它是指计算机与外部世界或者一个程序与计算机的其余部分的之间的接口.它对于任何计算机系统都非常关键,因而所有 I/O 的主体实际上是内置在操作系统中的.单独的程序一般是让系统为它们完成大部分的工作. 在 Java 编程中,直到最近一直使用 流 的方式完成 I/O.所有 I/O 都被视为单个的字节的移动,通过一个称为 Stream 的对象一次移动一个字节.流 I/O 用于与外部世界接触.它也在内部使用,用于将

  • 浅谈Java中BIO、NIO和AIO的区别和应用场景

    最近一直在准备面试,为了使自己的Java水平更上一个档次,拜读了李林峰老师的<Netty权威指南>,了解了Java关于IO的发展和最新的技术,真是受益匪浅,现在把我总结的关于BIO.NIO和AIO的区别和应用场景概述一遍. 在此之前,先弄清几个概念: 1.同步:使用同步IO时,Java自己处理IO读写. 2.异步:使用异步IO时,Java将IO读写委托给OS处理,需要将数据缓冲区地址和大小传给OS,完成后OS通知Java处理(回调). 3.阻塞:使用阻塞IO时,Java调用会一直阻塞到读写完成

  • Java BIO,NIO,AIO总结

    Java 中的 BIO.NIO和 AIO 理解为是 Java 语言对操作系统的各种 IO 模型的封装.程序员在使用这些 API 的时候,不需要关心操作系统层面的知识,也不需要根据不同操作系统编写不同的代码.只需要使用Java的API就可以了. 在讲 BIO,NIO,AIO 之前先来回顾一下这样几个概念:同步与异步,阻塞与非阻塞. 同步与异步 同步: 同步就是发起一个调用后,被调用者未处理完请求之前,调用不返回. 异步: 异步就是发起一个调用后,立刻得到被调用者的回应表示已接收到请求,但是被调用者

  • java中BIO、NIO、AIO都有啥区别

    一.BIO(Blocking IO,也被称作old IO) 同步阻塞模型,一个客户端连接对应一个处理线程 对于每一个新的网络连接都会分配给一个线程,每隔线程都独立处理自己负责的输入和输出, 也被称为Connection Per Thread模式 缺点: 1.IO代码里read操作是阻塞操作,如果连接不做数据读写操作会导致线程阻塞,浪费资源 2.如果线程很多,会导致服务器线程太多,压力太大,比如C10K问题 所谓c10k问题,指的是服务器同时支持成千上万个客户端的问题,也就是concurrent

  • JavaIO模型中的BIO,NIO和AIO详解

    目录 一.I/O模型 1.1 I/O模型基本说明 1.2 Java支持的3种网络编程I/O模式 1.3 JavaBIO(同步阻塞) 1.4 JavaNIO (同步非阻塞) 1.5 JavaAIO(异步非阻塞) 二.BIO.NIO.AIO适用场景分析 2.1 BIO应用场景 2.2 NIO应用场景 2.3 AIO应用场景 总结 一.I/O模型 1.1 I/O模型基本说明 I/O模型的简单理解:I/O模型就是用什么样的通道进行数据的发送和接受,很大程度上决定了程序通信的性能 1.2 Java支持的3

  • Java中实现线程的三种方式及对比_动力节点Java学院整理

    Java中创建线程主要有三种方式: 一.继承Thread类创建线程类 (1)定义Thread类的子类,并重写该类的run方法,该run方法的方法体就代表了线程要完成的任务.因此把run()方法称为执行体. (2)创建Thread子类的实例,即创建了线程对象. (3)调用线程对象的start()方法来启动该线程. package com.thread; public class FirstThreadTest extends Thread{ int i = 0; //重写run方法,run方法的方

  • Java中线程Thread的三种方式和对比

    介绍 多线程主要的作用就是充分利用cpu的资源.单线程处理,在文件的加载的过程中,处理器就会一直处于空闲,但也被加入到总执行时间之内,串行执行切分总时间,等于每切分一个时间*切分后字符串的个数,执行程序,估计等几分钟能处理完就不错了.而多线程处理,文件加载与差分过程中 一.Java实现多线程的三种方式 1.继承Thread 通过Thread继承,并重写run方法来实现多线程,案例如下: public class ThreadPattern extends Thread { @Override p

  • 详解Java 网络IO编程总结(BIO、NIO、AIO均含完整实例代码)

    本文会从传统的BIO到NIO再到AIO自浅至深介绍,并附上完整的代码讲解. 下面代码中会使用这样一个例子:客户端发送一段算式的字符串到服务器,服务器计算后返回结果到客户端. 代码的所有说明,都直接作为注释,嵌入到代码中,看代码时就能更容易理解,代码中会用到一个计算结果的工具类,见文章代码部分. 相关的基础知识文章推荐: Linux 网络 I/O 模型简介(图文) Java 并发(多线程) 1.BIO编程 1.1.传统的BIO编程 网络编程的基本模型是C/S模型,即两个进程间的通信. 服务端提供I

  • Java文件读写IO/NIO及性能比较详细代码及总结

    干Java这么久,一直在做WEB相关的项目,一些基础类差不多都已经忘记.经常想得捡起,但总是因为一些原因,不能如愿. 其实不是没有时间,只是有些时候疲于总结,今得空,下定决心将丢掉的都给捡起来. 文件读写是一个在项目中经常遇到的工作,有些时候是因为维护,有些时候是新功能开发.我们的任务总是很重,工作节奏很快,快到我们不能停下脚步去总结. 文件读写有以下几种常用的方法 1.字节读写(InputStream/OutputStream) 2.字符读取(FileReader/FileWriter) 3.

  • Java中数组转List的三种方法与对比分析

    前言: 本文介绍Java中数组转为List三种情况的优劣对比,以及应用场景的对比,以及程序员常犯的类型转换错误原因解析. 一.最常见方式(未必最佳) 通过 Arrays.asList(strArray) 方式,将数组转换List后,不能对List增删,只能查改,否则抛异常. 关键代码:List list = Arrays.asList(strArray); private void testArrayCastToListError() { String[] strArray = new Stri

  • Java中获取时间戳的三种方式对比实现

    Java中获取时间戳 三种方式对比 最近项目开发过程中发现了项目中获取时间戳的业务.而获取时间戳有以下三种方式,首先先声明推荐使用System类来获取时间戳,下面一起看一看三种方式. 1.System.currentTimeMillis() System类中的currentTimeMillis()方法是三种方式中效率最好的,运行时间最短.开发中如果设计到效率问题,推荐使用此种方式获取. System.currentTimeMillis() 2.new Date().getTime() 除了Sys

  • 浅谈Java中IO和NIO的本质和区别

    IO的本质 IO的作用就是从外部系统读取数据到java程序中,或者把java程序中输出的数据写回到外部系统.这里的外部系统可能是磁盘,网络流等等. 因为对所有的外部数据的处理都是由操作系统内核来实现的,对于java应用程序来说,只是调用操作系统中相应的接口方法,从而和外部数据进行交互. 所有IO的本质就是对Buffer的处理,我们把数据放入Buffer供系统写入外部数据,或者从系统Buffer中读取从外部系统中读取的数据.如下图所示: 用户空间也就是我们自己的java程序有一个Buffer,系统

  • java基于netty NIO的简单聊天室的实现

    一.为何要使用netty开发 由于之前已经用Java中的socket写过一版简单的聊天室,这里就不再对聊天室的具体架构进行细致的介绍了,主要关注于使用netty框架重构后带来的改变.对聊天室不了解的同学可以先看下我的博客(<JAVA简单聊天室的实现>) 本篇博客所使用的netty版本为4.1.36,完整工程已上传到Github(https://github.com/Alexlingl/Chatroom),其中lib文件夹下有相应的netty jar包和source包,自行导入即可. 1.为何要

随机推荐