1. Concepts de base
IO est le processus de copie des données par la mémoire principale et les dispositifs externes (disques durs, terminaux, réseaux, etc.). IO est l'implémentation fonctionnelle sous-jacente du système d'exploitation, qui est terminée par le biais d'instructions d'E / S.
Tous les systèmes d'exécution linguistique fournissent des outils de haut niveau pour effectuer des E / S. (C's PrintfScanf, l'encapsulation orientée objet de Java)
2. Revue de Java Standard IO
La bibliothèque de classe Java Standard IO est une abstraction orientée objet IO. Sur la base de la mise en œuvre sous-jacente des méthodes locales, nous n'avons pas besoin de prêter attention à la mise en œuvre sous-jacente. InputStream / OutputStream: transférez un octet à la fois. Lecteur / écrivain: un personnage à la fois.
3.NIO INTRODUCTION
Nio est l'abréviation de Javanewio, une nouvelle API fournie dans JDK1.4. Les caractéristiques que Sun prétend officiellement est la suivante:
Fournit une prise en charge du cache (tampon) pour tous les types primitifs.
Définir des solutions de codage et de décodage.
Channel: une nouvelle abstraction d'E / S originale.
Prend en charge les interfaces d'accès aux fichiers pour les fichiers mappés de verrouillage et de mémoire.
Fournit des E / S de réseau non bloquantes, non bloquantes et hautement évolutives.
Cet article apprendra et présentera ces fonctionnalités.
4.Buffer & Chanel
Le canal et le tampon sont NIO et sont les deux abstractions de type de données les plus élémentaires.
Tampon:
C'est un bloc de mémoire continu.
C'est le lieu de transit pour la lecture ou l'écriture des données NIO.
Canal:
La source de données ou de destination des données
Une interface unique pour fournir des données aux tampons ou des données de tampon de lecture, des objets de tampon.
Support d'E / S asynchrone
Exemple 1: CopyFile.java:
Échantillon de package; import java.io.fileInputStream; import java.io.fileoutputStream; import java.nio.bytebuffer; importer java.nio.channels.filechannel; classe publique CopyFile {public static void main (string [] args) lance exception {string infile = "c: //copy. "C: //copy.txt"; // Obtenez des flux d'entrée et de sortie des fichiers source et cible FileInputStream Fin = new FileInputStream (Infile); FileOutputStream fout = new FileOutputStream (OutFile); // Obtenez des canaux d'entrée et de sortie FileChannel FCIN = Fin.getChannel () tampon = bytebuffer.ALLOCY (1024); tandis que (true) {// Clear Method réinitialise le tampon afin qu'il puisse accepter les données de lecture Buffer.Clear (); // Lire les données du canal d'entrée vers le tampon int r = fcin.read (tampon); // la méthode de lecture renvoie le nombre d'octets lus, qui peut être zéro, si le canal a atteint la fin du flux, le buffer If (r == -1) {Break;} Données nouvellement lues à un autre canal buffer.flip (); // Écrivez les données du canal de sortie vers le tampon fcot.write (tampon);}}}La structure interne du tampon est la suivante (la figure suivante est copiée à partir des informations):
Figure 2: Tampon Structure interne
Un tampon contrôle principalement le processus de lecture et d'écriture par trois variables position, limite et capacité. La signification de ces trois variables est indiquée dans le tableau suivant:
paramètre | Mode d'écriture | Mode de lecture |
position | Le nombre de données unitaires actuellement écrites. | L'emplacement actuel des données de l'unité lue. |
limite | Il représente le nombre maximal d'unités de données et de capacité qui peuvent être écrites est la même. | Il représente le nombre maximum d'unités de données qui peuvent être lues, ce qui est cohérent avec la quantité de données unitaires écrites auparavant. |
capacité | Tampon | Tampon |
Méthodes de tampon courantes:
flip (): convertir le mode écriture en mode de lecture
Rewind (): réinitialiser la position à 0, généralement utilisée pour la lecture répétée.
Clear (): effacez le tampon et préparez-vous à être réécrit (la position devient 0, la limite devient la capacité).
compact (): copier les données non lues à la tête du tampon.
mark (), reset (): Mark peut marquer une position, la réinitialisation peut être réinitialisée à cette position.
Types communs de tampon: bytebuffer, mappedbytebuffer, charbuffer, doublebuffer, floatbuffer, intbuffer, longbuffer, shortbuffer.
Canaux communs: FileChannel, DatagramChannel (UDP), Socketchannel (TCP), Serversocketchannel (TCP)
Un test de performance simple a été effectué sur cette machine. Mon ordinateur portable fonctionne avec modération. (Voir la pièce jointe du code spécifique. Voir l'exemple ci-dessous dans le package Nio.sample.FileCopy) Ce qui suit est les données de référence:
Scénario 1: Copiez un fichier de 370 m
Scénario 2: trois threads copient en même temps, chaque thread copie un fichier 370m.
Scène | FileInputStream + FileoutputStream | FileInputStream + BufferedInputStream + FileoutputStream | Bytebuffer + Filechanal | Mappé parbuffer + Filechannel |
Scène pendant un certain temps (millisecondes) | 25155 | 17500 | 19000 | 16500 |
Scène 2 fois (millisecondes) | 69000 | 67031 | 74031 | 71016 |
5.Nio.Charset
Encodage et décodage de caractère: Bytecode lui-même n'est que quelques nombres, qui sont correctement analysés dans le bon contexte. Lorsque vous stockez des données dans ByteBuffer, vous devez considérer la méthode de codage du jeu de caractères. Lorsque vous lisez et affichez des données ByteBuffer, vous impliquez le décodage du jeu de caractères.
Java.nio.Charset fournit un ensemble de solutions pour le codage et le décodage.
Prenant l'exemple de notre demande HTTP la plus courante, la demande doit être codée correctement lors de la demande. La réponse doit être correctement décodée lorsqu'elle est obtenue.
Le code suivant envoie une demande à Baidu et obtient les résultats pour l'affichage. L'exemple démontre l'utilisation de Charset.
Exemple 2BaiduReader.java
package nio.readpage; import java.nio.bytebuffer; import java.nio.channels.socketchannel; import java.nio.charset.charse; import java.net.inetsocketddress; import java.io.ioexception; Socketchannel Channel; public void readhtmlContent () {try {inetsocketAddress socketAddress = new InetsocketAddress ("www.baidu.com", 80); // Step1: Ouvrez la chaîne de connexion = Socketchannel.open (socketaddress); // Step2: Envoyer la demande, Encode Channel.Write (Charset.ende ("Get" + "/ / / / / / / / / / / / / / / /" Http / 1.1 "+" / r / n / r / n ")); // Step3: Lisez les données ByteBuffer Buffer = ByteBuffer.Allocate (1024); // Créer un tampon 1024-byte while (Channel.Read (Buffer)! = -1) {Buffer.flip (); // La méthode de flip est appelée avant l'opération Byte du tampon. System.out.println (charset.decode (buffer)); // Utilisez la méthode charset.decode pour convertir les octets en chaîne buffer.clear (); // clear buffer}} catch (ioException e) {System.err.println (e.toString ());} enfin {if (channel! = Null) {Try {channel.close ();} Catch (ioxception) {Try {channel.close (); e) {}}}} public static void main (String [] args) {new baidureader (). readhtmlcontent ();}}6. IO non bloquant
En ce qui concerne l'OI non bloquant, nous comprendrons à partir des aspects de ce qui bloque, de ce qui est non bloquant, du principe non bloquant et de l'API centrale asynchrone.
Qu'est-ce que le blocage?
Un processus de communication IO de réseau commun est le suivant:
À partir de ce processus de communication réseau, comprenons ce qu'est le blocage:
Si la connexion n'est pas arrivée dans le processus ci-dessus, Accepter sera bloquer, le programme devra s'accrocher après l'exécution ici et le CPU exécutera à la place d'autres threads.
Si les données ne sont pas prêtes dans le processus ci-dessus, la lecture bloque également.
Caractéristiques du blocage du réseau IO: plusieurs connexions multiples. Chaque fil a son propre espace de pile et prend du temps CPU. Chaque thread se bloque lorsqu'il rencontrera un prêt externe. Le résultat du blocage est qu'il conduira à un grand nombre de commutations de contexte de processus. Et la plupart des changements de contexte de processus peuvent être dénués de sens. Par exemple, supposons qu'un thread écoute un port, et qu'il n'y aura que quelques demandes en une journée, mais le CPU doit constamment faire des tentatives de commutation de contexte pour le thread, et la majeure partie de la commutation se termine par le blocage.
Qu'est-ce que non bloquant?
Voici une métaphore:
Dans un bus de A à B, il y a de nombreux points sur la route qui peuvent s'en sortir. Le conducteur ne sait pas quels points vont sortir du bus. Comment gérer ceux qui ont besoin de mieux descendre du bus?
1. Pendant le processus, le conducteur demande régulièrement à chaque passager s'il est arrivé à destination. Si quelqu'un le dit, le conducteur s'arrête et le passager descend. (Similaire au blocage)
2. Tout le monde dit au vendeur de billets sa destination puis dort. Le conducteur n'interagit qu'avec le vendeur de billets. Quand il arrive à un certain point, le vendeur de billets informera le passager de quitter le bus. (Similaire au non-bloquant)
De toute évidence, tout le monde pour atteindre une destination peut être considéré comme un fil, et le conducteur peut être considéré comme un processeur. Dans le style de blocage, chaque fil doit constamment interroger et changer de contexte pour obtenir le résultat de la recherche de la destination. En mode non bloquant, chaque passager (fil) dort (dort) et ne se réveille que lorsque l'environnement externe réel est prêt. Un tel réveil ne bloquera certainement pas.
Le principe de non-bloquant
Passez l'ensemble du processus en petites tâches et complétez-la grâce à la collaboration entre les tâches.
Un fil dédié gère tous les événements IO et est responsable de la distribution.
Mécanisme axé sur les événements: déclenche lorsqu'un événement arrive, plutôt que de surveiller les événements simultanément.
Communication du thread: les threads communiquent via Wait, Notify et d'autres moyens. Assurez-vous que chaque commutateur de contexte est logique. Réduisez la commutation de processus inutile.
Ce qui suit est la structure de l'OI asynchrone:
Le réacteur est le rôle métaphorique ci-dessus du vendeur de billets. Le flux de traitement de chaque thread consiste probablement à lire les données, à décoder, à calculer le traitement, à coder et à envoyer des réponses.
API Core IO asynchrone
Sélecteur
La classe de base de l'OI asynchrone, qui peut détecter les événements sur un ou plusieurs canaux et distribuer des événements.
Utilisez un thread Select pour écouter des événements sur plusieurs canaux et déclenchez des réponses correspondantes en fonction des pilotes d'événements. Il n'est pas nécessaire d'allouer un fil pour chaque canal.
Sélection de sélection
Contient la liaison du canal correspondant aux informations d'état de l'événement et de l'heure.
Résumer
Ce qui précède est l'intégralité du contenu de cet article sur les essais de connaissances Java de base, j'espère que cela sera utile à tout le monde. Les amis intéressés peuvent continuer à se référer à d'autres sujets connexes sur ce site. S'il y a des lacunes, veuillez laisser un message pour le signaler. Merci vos amis pour votre soutien pour ce site!