Heim  >  Artikel  >  Java  >  Vergleichende Analyse von Java-Eingabe- und Ausgabe-IO, NIO und AIO

Vergleichende Analyse von Java-Eingabe- und Ausgabe-IO, NIO und AIO

王林
王林nach vorne
2023-05-08 23:07:071543Durchsuche

    1. Geschichte der Java-I/O-Entwicklung

    Vergleichende Analyse von Java-Eingabe- und Ausgabe-IO, NIO und AIO

    Java IO (Input/Output) ist eine API zum Lesen und Schreiben von Daten in der Java-Sprache. Sie stellt eine Reihe von Klassen und Schnittstellen zum Lesen und Schreiben bereit Schreiben Sie verschiedene Arten von Daten. Das Folgende ist eine kurze Einführung in die Entwicklungsgeschichte von Java IO:

    • JDK 1.0 (1996) Das ursprüngliche Java IO unterstützte nur Byteströme (InputStream, OutputStream) und Zeichenströme (Reader, Writer), basierend auf blockierendem IO ( BIO)-Modell.

    • JDK 1.1 (1997) JDK 1.1 führte das NIO-Paket (New IO) ein, unterstützte Konzepte wie Puffer und Kanal, stellte eine effizientere IO-Betriebsmethode bereit und konnte einen nicht blockierenden IO-Modus (NIO) erreichen.

    • JDK 1.4 (2002) JDK 1.4 fügt die NIO.2-API, auch bekannt als Java NIO, mit Puffern hinzu und bietet leistungsfähigere Dateiverarbeitungsfunktionen und effizientere E/A-Vorgänge.

    • JDK 7 (2011) JDK 7 führt eine verbesserte Version von NIO.2 ein – NIO.2 mit Completion Ports, auch bekannt als AIO (Asynchronous IO), das den asynchronen IO-Modus unterstützt und eine große Anzahl gleichzeitiger Anforderungen verarbeiten kann . hat einen Vorteil.

    Das Folgende sind die Unterschiede zwischen den drei:

    Vergleichende Analyse von Java-Eingabe- und Ausgabe-IO, NIO und AIO

    • Blocking IO (BIO) BIO ist Javas ursprüngliches IO-Modell, das Blockierungsmethoden für Datenlese- und -schreibvorgänge verwendet. Das heißt, wenn ein Thread einen E/A-Vorgang ausführt und keine Daten zum Lesen vorhanden sind, blockiert der Thread und wartet, bis Daten zum Lesen vorhanden sind, oder es kommt zu einer Zeitüberschreitung. BIO eignet sich für Szenarien, in denen die Anzahl der Verbindungen relativ gering und fest ist, die Parallelitätsfähigkeit jedoch unzureichend ist.

    • Nicht blockierendes IO (NIO) NIO ist ein neues IO-Modell, das in Java 1.4 eingeführt wurde. Es verwendet einen Multiplexer-Mechanismus (Selektor), um mehrere Kanäle gleichzeitig über eine kleine Anzahl von Threads zu verwalten, sodass ein einzelner Thread dies tun kann Mehrere Kanäle gleichzeitig verarbeiten Die Wirkung einer Anfrage. NIO verfügt über eine hohe Parallelität, einen hohen Durchsatz und eine höhere Zuverlässigkeit und eignet sich für die Handhabung von Szenarien mit einer großen Anzahl von Verbindungen und kurzen Verbindungszeiten.

    • Asynchronous IO (AIO) AIO ist ein von Java 1.7 unterstütztes IO-Modell. Es verwendet einen ereignisgesteuerten Ansatz zum Lesen und Schreiben von Daten. Wenn die Daten bereit sind, werden sie in der Callback-Funktion verarbeitet. Im Gegensatz zu NIO sind die Lese- und Schreibvorgänge von AIO asynchron und es ist keine Abfrage erforderlich, um zu prüfen, ob die Daten bereit sind. AIO eignet sich für Szenarien mit einer großen Anzahl von Verbindungen, langen Verbindungszeiten und vielen Lese- und Schreibvorgängen.

    2. Java IO

    2.1 Einführung

    In der Java-Programmierung sind IO-Operationen (Eingabe/Ausgabe) sehr häufige Operationen, die das Lesen und Schreiben von Dateien, die Netzwerkkommunikation usw. umfassen. Java stellt verschiedene Klassen zur Unterstützung dieser Operationen bereit. Dieser Artikel beginnt mit den Grundkenntnissen von IO und geht dann schrittweise in die Tiefe, um alle Aspekte von Java IO vorzustellen.

    2.2 Grundkonzepte

    2.2.1 Eingabestream und Ausgabestream

    In Java sind Eingabestream (InputStream) und Ausgabestream (OutputStream) zwei wichtige abstrakte Klassen. Der Eingabestream stellt die Quelle der Eingabedaten dar, bei denen es sich um Dateien, Netzwerkverbindungen, Pipes usw. handeln kann. Der Ausgabestream stellt das Ziel der Ausgabedaten dar, bei denen es sich um Dateien, Netzwerkverbindungen, Pipes usw. handeln kann. Eingabe- und Ausgabestreams werden auf ähnliche Weise verwendet, indem ein Stream-Objekt erstellt und dann die entsprechende Methodenschnittstelle zum Ausführen von Lese- und Schreibvorgängen verwendet wird.

    2.2.2 Byte-Stream und Zeichen-Stream

    E/A-Operationen in Java können auch in zwei Typen unterteilt werden: Byte-Stream und Zeichen-Stream. Der Bytestrom arbeitet in Einheiten von Bytes (Byte) und eignet sich für die Verarbeitung von Binärdaten wie Bildern, Audio usw., während der Zeichenstrom in Einheiten von Zeichen (Char) arbeitet und für die Verarbeitung von Textdaten geeignet ist Textdateien usw. In Java werden Byteströme hauptsächlich von den Klassen InputStream und OutputStream und ihren Unterklassen implementiert, während Zeichenströme hauptsächlich von den Klassen Reader und Writer und ihren Unterklassen implementiert werden.

    2.2.3 Gepufferter Stream

    Bei der Durchführung von E/A-Vorgängen müssen wir möglicherweise häufige Lese- und Schreibvorgänge ausführen, und häufiges Lesen und Schreiben kann zu Leistungsproblemen führen. Um dieses Problem zu lösen, stellt Java einen gepufferten Stream (Buffered Stream) bereit, um die Effizienz von E/A-Vorgängen zu verbessern. Gepufferte Streams können die Anzahl der Zugriffe auf zugrunde liegende Ressourcen über den internen Cache-Bereich reduzieren und dadurch die Effizienz beim Lesen und Schreiben von Daten verbessern.

    2.3 Verwendung von Java IO

    2.3.1 Lesen und Schreiben von Dateien

    Das Lesen und Schreiben von Dateien in Java ist einer der häufigsten Vorgänge in der Entwicklung. Das Folgende ist ein Beispiel für das Lesen und Ausgeben des Inhalts einer Datei:

        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();
        }

    In diesem Beispiel verwenden wir Klassen wie FileInputStream, InputStreamReader und BufferedReader, um das Lesen der Datei abzuschließen. Zuerst erstellen wir über die FileInputStream-Klasse ein Eingabestream-Objekt und geben den Namen der zu lesenden Datei an. Anschließend konvertieren wir den Bytestream mit InputStreamReader in einen Zeichenstream und lesen dann mit BufferedReader den Textinhalt Zeile für Zeile.

    Ebenso ist das Schreiben von Dateien in Java auch sehr einfach. Hier ist ein Beispiel für das Schreiben einer Datei:

    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 Das Prinzip von Java AIO

    Java AIO verwendet asynchrones IO zum Lesen und Schreiben von Daten. Im Gegensatz zu Java NIO muss nicht abgefragt werden, ob die Daten bereit sind, sondern durch das Betriebssystem. Wenn die Daten bereit sind, benachrichtigt das Betriebssystem die Anwendung und verarbeitet sie in der Rückruffunktion.

    AIO verwendet drei Kernkomponenten: AsynchronousChannel, CompletionHandler und
    AsynchronousServerSocketChannel. Unter diesen ist AsynchronousChannel der Kanal zum Lesen/Schreiben von Daten, CompletionHandler ist die Rückrufmethode, wenn der E/A-Vorgang abgeschlossen ist, und AsynchronousServerSocketChannel ist der asynchrone serverseitige Socket-Kanal, der zur Überwachung der Verbindungsanforderung des Clients verwendet wird.

    Wenn die Daten bereit sind, benachrichtigt das Betriebssystem die Anwendung und führt die Rückrufmethode in der Rückruffunktion aus, wenn der E/A-Vorgang abgeschlossen ist. Dies vermeidet die Situation, in der Threads blockiert werden und auf den Abschluss von E/A-Vorgängen warten, wodurch die Effizienz und die gleichzeitigen Verarbeitungsfähigkeiten des Programms verbessert werden.

    4.2 Funktionen von Java AIO

    • Hohe Parallelität: Java AIO verwendet asynchrone E/A für Datenlese- und -schreibvorgänge, wodurch eine Verarbeitung mit hoher Parallelität erreicht werden kann Fähigkeit.

    • Hoher Durchsatz: Java AIO unterstützt asynchrone Lese- und Schreibvorgänge und kann mehrere Anforderungen gleichzeitig verarbeiten, wodurch die Effizienz und der Durchsatz beim Lesen und Schreiben von Daten verbessert werden.

    • Hohe Zuverlässigkeit: Da Java AIO asynchrone E/A für Datenlese- und -schreibvorgänge verwendet, kann das Blockieren von Threads beim Warten auf den Abschluss von E/A-Vorgängen vermieden werden, wodurch die Leistung des Programms verbessert wird Leistungszuverlässigkeit.

    • Einfach zu verwenden: Java AIO bietet eine einfache und benutzerfreundliche API, und Sie können asynchrone E/A-Vorgänge implementieren, ohne komplexen Code schreiben zu müssen.

    4.3 Anwendung von Java AIO

    Java AIO eignet sich für Szenarien, die eine große Anzahl gleichzeitiger Verbindungen erfordern, jede Verbindung jedoch nur wenige Daten enthält Interaktion, wie nachrichtenbasierte Anwendungen, Remote Procedure Calls (RPC) usw. In diesen Anwendungsszenarien kann AIO die Leistung und die gleichzeitigen Verarbeitungsfähigkeiten des Programms erheblich verbessern und so die Anforderungen der Benutzer nach hohem Durchsatz und geringer Latenz erfüllen.

    Darüber hinaus kann Java AIO auch zur Entwicklung leistungsstarker Netzwerkserver wie Chatroom-Server, Online-Game-Server usw. verwendet werden. Da AIO das asynchrone Lesen von Eingabe- und Ausgabeströmen unterstützt, kann es mehrere Clientanforderungen gleichzeitig verarbeiten und so die gleichzeitigen Verarbeitungsfähigkeiten des Servers effektiv verbessern.

    Zusammenfassung

    Java AIO hat als leistungsstarkes IO-Modell mit hoher Parallelität viele Vorteile, weist aber auch einige Nachteile auf, beispielsweise die Anbindung kleiner Lasten , AIO Der Overhead kann zu Leistungseinbußen führen. Daher müssen in praktischen Anwendungen verschiedene Faktoren abgewogen und bewertet und basierend auf den tatsächlichen Bedürfnissen ausgewählt werden.

    5. Verwandte Interviewfragen

    1 Was sind Java IO und NIO?

    Java IO (Input/Output) ist eine traditionelle Eingabe- und Ausgabeoperation in Java, die Byteströme und Zeichenströme für die Datenübertragung verwendet.
    Java NIO (New Input/Output) ist eine neue Eingabe- und Ausgabe-API, die in Java 1.4 eingeführt wurde und Daten effizienter verarbeitet.

    2. Was sind blockierende und nicht blockierende IO?

    Blocking IO wartet, bis das IO während des IO-Vorgangs abgeschlossen ist. Während dieser Zeit können keine anderen Vorgänge ausgeführt werden.
    Non-blocking IO (Non-blocking IO) wartet bei der Ausführung von IO-Vorgängen nicht ewig, sondern gibt das Ergebnis sofort zurück. Wenn der IO noch nicht vollständig abgeschlossen ist, können Sie mit anderen Dingen fortfahren.

    3. Was ist eine Pufferzone? Welche Arten von Puffern gibt es?

    Der Puffer ist ein Array zum Speichern von Daten. Bei der Durchführung von E/A-Vorgängen muss der Puffer zum Lesen und Schreiben von Daten verwendet werden.
    Java-Puffer sind in Byte-Puffer (ByteBuffer, CharBuffer, ShortBuffer usw.) und direkte Puffer (DirectByteBuffer, DirectCharBuffer, DirectShortBuffer usw.) unterteilt.

    4. Was ist Kanal?

    Ein Kanal ist ein Objekt, das zur Datenübertragung in NIO verwendet wird. Er kann zum Lesen und Schreiben von Daten mit einem Quell- oder Zielknoten verbunden werden.

    5. Was ist ein Selektor?

    Der Selektor ist ein Objekt in NIO. Er kann die darauf registrierten Kanäle abfragen, um zu überprüfen, ob sie Ereignisse haben (z. B. lesbar, beschreibbar usw.), wodurch das Blockieren vermieden wird. Das Problem, warten zu müssen damit IO in IO abgeschlossen werden kann.

    6. Was ist der Unterschied zwischen Java IO und NIO?

    Java IO überträgt Daten basierend auf Streams, während NIO Daten basierend auf Puffern und Kanälen überträgt.
    Java IO blockiert, während NIO im blockierenden oder nicht blockierenden Modus sein kann.
    Java IO verwendet mehr Threads und jede IO-Operation erfordert die Erstellung eines Threads, während NIO einen einzelnen Thread verwenden kann, um mehrere IO-Operationen abzuwickeln.

    7. Was ist FileChannel?

    Der Dateikanal ist ein Kanal in NIO, der zum Lesen und Schreiben von Dateien verwendet wird. Er unterstützt erweiterte Funktionen wie Direktzugriff und speicherzugeordnete Dateien.

    8. Welches ist schneller, Java IO oder NIO?

    Bei großen Mengen kleiner Daten ist Java IO möglicherweise schneller, da alle Daten auf einmal über den Puffer gelesen werden können.
    Bei einer großen Anzahl großer Datenblöcke ist NIO möglicherweise schneller, da es die Zero-Copy-Technologie verwenden kann, um Daten direkt von der Festplatte in den Speicher zu lesen und so den Aufwand für das Datenkopieren zu reduzieren.

    Das obige ist der detaillierte Inhalt vonVergleichende Analyse von Java-Eingabe- und Ausgabe-IO, NIO und AIO. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Stellungnahme:
    Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen