English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

Articles divers sur les bases de Java

1Concepts de base

IO est le processus de copie de données entre la mémoire principale et les périphériques externes (disques durs, terminaux et réseaux, etc.). IO est une fonctionnalité de basse couche de l'exploitation système, basée sur l'instruction I/Pour terminer.

Tous les systèmes d'exécution de langage fournissent l'exécution de l'instruction I/O outils de niveau supérieur. (printf scanf de c, encapsulation orientée objet de java)

2.Révision de l'IO standard Java

La bibliothèque de classes IO standard de Java est une abstraction orientée objet pour IO. Basée sur l'implémentation sous-jacente des méthodes locales, nous n'avons pas besoin de nous soucier de l'implémentation sous-jacente. InputStream\OutputStream (flux de bytes) : Transmet un byte à la fois. Reader\Writer (flux de caractères) : Un caractère à la fois.

3.Introduction à nio

nio est l'abréviation de javaNewIO, dans jdk1.4Les nouvelles API fournies dans Sun sont les suivantes :

– Fournit un support de cache (Buffer) pour tous les types de données primaires.

– Solution de codage/décodage de jeu de caractères.

– Channel : Un nouveau type d'interface de données en entrée/sortie directe/O abstraction.

– Interface de lecture/écriture de fichiers supportant les verrous et les fichiers mappés en mémoire.

– Fournit des connexions multiples (non-bloking) Réseau I de haute élasticité non bloquant/O.

Ce document se concentrera sur ces caractéristiques pour l'apprentissage et l'introduction.

4.Buffer&Chanel

Channel et buffer sont deux types de données abstraits de base dans NIO.

Buffer:

– Est un bloc de mémoire contigu.

– Est un intermédiaire pour la lecture ou l'écriture de données NIO.

Channel:

– Source ou destination des données

– Interface unique pour fournir des données au buffer ou lire des données du buffer, l'interface unique de l'objet buffer.

– Asynchrone I/O supporte

例子 1:CopyFile.java:

package sample;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
public class CopyFile {
	public static void main(String[] args) throws Exception {
		String infile = "C:\\copy.sql";
		String outfile = "C:\\copy.txt";
		// Obtenir les flux d'entrée/sortie des fichiers source et cible 
		FileInputStream fin = new FileInputStream(infile);
		FileOutputStream fout = new FileOutputStream(outfile);
		// Obtenir le canal d'entrée/sortie 
		FileChannel fcin = fin.getChannel();
		FileChannel fcout = fout.getChannel();
		// Création du buffer 
		ByteBuffer buffer = ByteBuffer.allocate(1024);
		while (true) {
			// La méthode clear réinitialise le buffer, le rendant prêt à recevoir les données lues 
			buffer.clear();
			// Lise les données du canal d'entrée dans le buffer 
			int r = fcin.read(buffer);
			// Le méthode read retourne le nombre d'octets lus, peut être nul, si le canal a atteint la fin du flux, alors retourne-1 
			if (r == -1) {
				break;
			}
			// La méthode flip permet au buffer de pouvoir écrire les données lues dans un autre canal 
			buffer.flip();
			// Écrit les données du canal de sortie dans le buffer 
			fcout.write(buffer);
		}
	}
}

La structure interne du buffer est la suivante (l'image ci-dessous est copiée de la documentation) :

image2structure interne du buffer

Un buffer est principalement contrôlé par trois variables : position, limit et capacity pour le processus de lecture et d'écriture. La signification de ces trois variables est indiquée dans le tableau suivant :

paramètres

Mode écriture    

Mode lecture

position

Nombre actuel de données unitaires écrites.

Position actuelle de la lecture des données unitaires.

limit

représente le nombre maximum de données unitaires que l'on peut écrire et est identique à la capacité.

représente le nombre maximum de données unitaires que l'on peut lire, et correspond à la quantité de données unitaires écrites précédemment.

capacity

capacité du buffer

capacité du buffer

Méthodes courantes de Buffer :

flip(): Convertit le mode d'écriture en mode lecture

rewind() : Réinitialise position à 0, généralement utilisé pour la lecture répétée.

clear() : Efface le buffer, prêt pour une autre écriture (position devient 0, limit devient capacité).

compact(): Copie les données non lues dans la tête du buffer.

mark()、reset(): mark peut marquer une position, reset peut réinitialiser à cette position.

Types courants de Buffer : ByteBuffer, MappedByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer.

Types courants de channel : FileChannel, DatagramChannel (UDP), SocketChannel (TCP), ServerSocketChannel (TCP)

Un ordinateur portable a été utilisé pour effectuer un test de performance simple. Les performances de mon ordinateur portable sont générales. (Le code détaillé peut être trouvé en annexe. Voir les exemples sous le paquet nio.sample.filecopy.) Voici les données de référence :

–场景1:Copy一个370M的文件

–场景2:三个线程同时拷贝,每个线程拷贝一个370M文件

场景

FileInputStream+

FileOutputStream

FileInputStream+

BufferedInputStream+

FileOutputStream

ByteBuffer+

FileChannel

MappedByteBuffer

+FileChannel

场景一时间 ( 毫秒)                 

25155

17500

19000

16500

场景二时间 ( 毫秒 )

69000

67031

74031

71016

5.nio.charset

字符编码解码:字节码本身只是一些数字,放到正确的上下文中被正确被解析。向ByteBuffer中存放数据时需要考虑字符集的编码方式,读取展示ByteBuffer数据时涉及对字符集解码。

Java.nio.charset提供了编码解码一套解决方案。

以我们最常见的http请求为例,在请求的时候必须对请求进行正确的编码。在得到响应时必须对响应进行正确的解码。

以下代码向baidu发一次请求,并获取结果进行显示。例子演示到了charset的使用。

例子2BaiduReader.java

package nio.readpage;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.nio.charset.Charset;
import java.net.InetSocketAddress;
import java.io.IOException;
public class BaiduReader {
	private Charset charset = Charset.forName("GBK");
	// 创建GBK字符集 
	private SocketChannel channel;
	public void readHTMLContent() {
		try {
			InetSocketAddress socketAddress = new InetSocketAddress( 
			"www.baidu.com", 80);
			//step1:打开连接 
			channel = SocketChannel.open(socketAddress);
			//step2:发送请求,使用GBK编码 
			channel.write(charset.encode("GET " + "/ HTTP/1.1" + "\r\n\r\n"));
			//step3:Lecture des données 
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			// Créer1024Tampon d'octets 
			while (channel.read(buffer) != -1) {
				buffer.flip();
				// Appeler la méthode flip avant l'opération des octets dans le tampon de lecture. 
				System.out.println(charset.decode(buffer));
				// Utiliser la méthode decode de Charset pour convertir les octets en chaîne 
				buffer.clear();
				// Vider le tampon
			}
		}
		catch (IOException e) {
			System.err.println(e.toString());
		}
		finally {
			if (channel != null) {
				try {
					channel.close();
				}
				catch (IOException e) {
				}
			}
		}
	}
	public static void main(String[] args) {
		new BaiduReader().readHTMLContent();
	}
}

6.IO non-blocage

Nous allons comprendre le IO non-blocage en termes de ce qu'est un blocage, ce qu'est un non-blocage, le principe du non-blocage et des API noyau asynchrones.

Qu'est-ce qu'un blocage ?

Un flux de communication IO réseau commun est le suivant :

Comprendre ce qu'est un blocage à partir de ce processus de communication réseau :

Dans le processus ci-dessus, si la connexion n'est pas venue, accept sera bloqué, et le programme doit s'arrêter ici, le CPU passant à l'exécution d'autres threads.

Dans le processus ci-dessus, si les données ne sont pas prêtes, read sera également bloqué.

Les caractéristiques d'un IO réseau en mode blocage : traitement par multithreading de plusieurs connexions. Chaque thread possède son propre espace de pile et utilise un certain temps CPU. Lorsque chaque thread rencontre une situation où l'extérieur n'est pas prêt, il est bloqué. Le résultat du blocage est qu'il y a beaucoup de passages de contexte de processus. Et la plupart des passages de contexte de processus peuvent être sans sens. Par exemple, supposons qu'un thread écoute un port, il ne peut y avoir qu'un certain nombre de demandes par jour, mais ce CPU doit constamment faire des tentatives de passage de contexte pour ce thread, la plupart des tentatives se terminant par un blocage.

Qu'est-ce qu'un non-blocage ?

Voici une métaphore :

Dans un autobus public allant d'A à B, il y a de nombreux points où des personnes peuvent descendre. Le conducteur ne sait pas quels points et quels passagers descendront, et comment traiter mieux les personnes qui doivent descendre?

1.Le conducteur demande à chaque passager pendant le trajet s'il est arrivé à son point de destination, si quelqu'un le dit, le conducteur arrête le véhicule et les passagers descendent. (Similaire à un blocage)

2.Chaque passager indique à l'agent de billetterie son point de destination, puis s'endort, le conducteur ne communique qu'avec l'agent de billetterie, et à un certain point, l'agent de billetterie informe les passagers de descendre. (Similaire à un non-blocage)

Il est évident que chaque personne pour atteindre un certain point de destination peut être considéré comme un fil, et le conducteur peut être considéré comme le CPU. Dans le cas de l'IO bloquant, chaque fil doit constamment faire des requêtes, des passages de contexte, pour atteindre le résultat de trouver le point de destination. Et dans le cas non bloquant, chaque passager (fil) dort (s'endort), ne se réveille que lorsque l'environnement externe est prêt, et ce réveil ne bloquera pas.

Principe non bloquant

Passer tout le processus en petites tâches, terminées par la collaboration entre les tâches.

Un thread spécial traite tous les événements d'IO et est responsable de la distribution.

Mécanisme d'événement déclenché : les événements déclenchent lorsque les événements arrivent, au lieu de surveiller les événements de manière synchrone.

Communication entre threads : les threads communiquent entre eux par wait, notify, etc. Assurez-vous que chaque passage de contexte est significatif. Réduire les changements de processus inutiles.

Voici la structure de l'IO asynchrone :

Le Reacteur est le rôle de guichetier隐喻 mentionné précédemment. Le flux de traitement de chaque fil est généralement lire des données, décodage, traitement de calcul, codage, envoyer une réponse.

API principale d'IO asynchrone

Selector

Classe principale d'IO asynchrone, elle peut détecter des événements sur un ou plusieurs canaux (channel) et distribuer les événements.

Il est possible d'écouter plusieurs événements sur plusieurs canaux avec une seule ligne de sélection et de déclencher des réponses appropriées sur la base de l'événement sans avoir besoin d'allouer une ligne pour chaque canal.

SelectionKey

Il contient des informations sur l'état de l'événement et le lien entre le canal et le temps.

Résumé

Voici le contenu complet de cet article sur les bases de Java, j'espère que cela vous aidera. Les amis intéressés peuvent continuer à consulter d'autres sujets pertinents sur ce site, et vous êtes les bienvenus pour laisser des commentaires si vous trouvez des insuffisances. Merci de votre soutien à ce site !

Déclaration : Le contenu de cet article est extrait du réseau, propriété de l'auteur original, le contenu est contribué et téléchargé par les utilisateurs d'Internet, ce site Web ne détient pas de propriété, n'a pas été traité par l'éditeur humain et n'assume aucune responsabilité juridique. Si vous trouvez du contenu suspect de droits d'auteur, veuillez envoyer un e-mail à : notice#w3Déclaration : Le contenu de cet article est extrait du réseau, propriété de l'auteur original, le contenu est contribué et téléchargé par les utilisateurs d'Internet, ce site Web ne détient pas de propriété, n'a pas été traité par l'éditeur humain et n'assume aucune responsabilité juridique. Si vous trouvez du contenu suspect de droits d'auteur, veuillez envoyer un e-mail à : notice#w

Vous pourriez aussi aimer