Maison  >  Article  >  Java  >  Analyse comparative des entrées et sorties Java IO, NIO et AIO

Analyse comparative des entrées et sorties Java IO, NIO et AIO

王林
王林avant
2023-05-08 23:07:071543parcourir

    1、Java I/O发展史    

    Analyse comparative des entrées et sorties Java IO, NIO et AIO

    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方式,在处理大量并发请求时具有优势。

    以下是三者之间的区别:

    Analyse comparative des entrées et sorties Java IO, NIO et AIO

    • 阻塞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 Principe de Java AIO

    Java AIO utilise des E/S asynchrones pour lire et écrire des données, contrairement à Java NIO, il n'a pas besoin d'interrogation pour vérifier si les données sont prêtes, mais sont complétées par le système d'exploitation. Lorsque les données sont prêtes, le système d'exploitation en informe l'application et les traite dans la fonction de rappel.

    AIO utilise trois composants principaux : AsynchronousChannel, CompletionHandler et
    AsynchronousServerSocketChannel. Parmi eux, AsynchronousChannel est le canal de lecture/écriture des données, CompletionHandler est la méthode de rappel lorsque l'opération d'E/S est terminée et AsynchronousServerSocketChannel est le canal de socket asynchrone côté serveur utilisé pour surveiller la demande de connexion du client.

    Lorsque les données sont prêtes, le système d'exploitation avertira l'application et exécutera la méthode de rappel dans la fonction de rappel lorsque l'opération d'E/S est terminée. Cela évite la situation dans laquelle les threads sont bloqués en attendant que les opérations d'E/S soient terminées, améliorant ainsi l'efficacité et les capacités de traitement simultané du programme.

    4.2 Caractéristiques de Java AIO

    • Concurrence élevée : Java AIO utilise des E/S asynchrones pour les opérations de lecture et d'écriture de données, ce qui peut atteindre des capacités de traitement simultanées élevées.

    • Haut débit : Java AIO prend en charge les opérations de lecture et d'écriture asynchrones et peut gérer plusieurs requêtes en même temps, améliorant ainsi l'efficacité et le débit de lecture et d'écriture des données.

    • Haute fiabilité : étant donné que Java AIO utilise des E/S asynchrones pour les opérations de lecture et d'écriture de données, il peut éviter le blocage des threads en attendant la fin des opérations d'E/S, améliorant ainsi la fiabilité du programme.

    • Simple et facile à utiliser : Java AIO fournit une API simple et facile à utiliser, et vous pouvez implémenter des opérations d'E/S asynchrones sans écrire de code complexe.

    4.3 Application de Java AIO

    Java AIO convient aux scénarios qui nécessitent un grand nombre de connexions simultanées, mais chaque connexion a peu d'interaction de données, comme les applications basées sur des messages, les appels de procédure à distance (RPC), etc. Dans ces scénarios d'application, l'AIO peut améliorer considérablement les performances et les capacités de traitement simultané du programme, répondant ainsi aux exigences des utilisateurs en matière de débit élevé et de faible latence.

    De plus, Java AIO peut également être utilisé pour développer des serveurs réseau hautes performances, tels que des serveurs de salons de discussion, des serveurs de jeux en ligne, etc. Étant donné qu'AIO prend en charge la lecture asynchrone des flux d'entrée et de sortie, il peut gérer plusieurs requêtes client en même temps, améliorant ainsi efficacement les capacités de traitement simultané du serveur.

    Résumé

    En tant que modèle IO hautes performances et haute concurrence, Java AIO présente de nombreux avantages, mais il présente également quelques inconvénients. Par exemple, pour les connexions avec de petites charges, la surcharge AIO peut entraîner une dégradation des performances. Par conséquent, dans les applications pratiques, divers facteurs doivent être pesés, évalués et sélectionnés en fonction des besoins réels.

    5. Questions d'entretien connexes

    1. Que sont Java IO et NIO ?

    Java IO (Input/Output) est une opération d'entrée et de sortie traditionnelle en Java, utilisant des flux d'octets et des flux de caractères pour la transmission de données.
    Java NIO (New Input/Output) est une nouvelle API d'entrée et de sortie introduite dans Java 1.4, qui traite les données plus efficacement.

    2. Que sont les IO bloquantes et non bloquantes ?

    Blocking IO (Blocking IO) attendra que l'IO soit terminé lors d'une opération IO, et aucune autre opération ne pourra être effectuée pendant cette période.
    Non-blocking IO (Non-blocking IO) n'attend pas indéfiniment lors de l'exécution d'opérations IO, mais renvoie le résultat immédiatement si l'IO n'est pas complètement terminé, vous pouvez continuer à faire d'autres choses.

    3. Qu'est-ce qu'une zone tampon ? Quels types de tampons existe-t-il ?

    Le tampon est un tableau utilisé pour stocker des données lors de l'exécution d'opérations d'E/S, le tampon doit être utilisé pour lire et écrire des données.
    Les tampons Java sont divisés en tampons d'octets (ByteBuffer, CharBuffer, ShortBuffer, etc.) et en tampons directs (DirectByteBuffer, DirectCharBuffer, DirectShortBuffer, etc.).

    4. Qu'est-ce que la chaîne ?

    Un canal est un objet utilisé pour la transmission de données dans NIO. Il peut être connecté à un nœud source ou destination pour lire et écrire des données.

    5. Qu'est-ce qu'un sélecteur ?

    Un sélecteur est un objet dans NIO. Il peut interroger les canaux enregistrés dessus pour vérifier s'ils ont des événements (tels que lisibles, inscriptibles, etc.), évitant ainsi d'avoir à attendre que l'IO se termine en bloquant le problème. .

    6. Quelle est la différence entre Java IO et NIO ?

    Java IO transmet des données basées sur des flux, tandis que NIO transmet des données basées sur des tampons et des canaux.
    Java IO est bloquant, tandis que NIO peut être en mode bloquant ou non bloquant.
    Java IO utilise plus de threads et chaque opération IO nécessite la création d'un thread, tandis que NIO peut utiliser un seul thread pour gérer plusieurs opérations IO.

    7. Qu'est-ce que FileChannel ?

    Les canaux de fichiers sont des canaux utilisés dans NIO pour lire et écrire des fichiers. Il prend en charge des fonctionnalités avancées telles que l'accès aléatoire et les fichiers mappés en mémoire.

    8. Lequel est le plus rapide, Java IO ou NIO ?

    Dans le cas de grandes quantités de petites données, Java IO peut être plus rapide car il peut lire toutes les données en même temps via le tampon.
    Dans le cas de gros blocs de données, NIO peut être plus rapide car il peut utiliser la technologie zéro copie pour lire les données directement du disque vers la mémoire, réduisant ainsi la surcharge de copie des données.

    Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

    Déclaration:
    Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer