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

Articolo vario di base Java

1. Concetti di base

L'I/O è il processo di copia dei dati tra la memoria principale e i dispositivi esterni (hard disk, terminali e reti, ecc.). L'I/O è un'implementazione di funzionalità di basso livello del sistema operativo, completata tramite comandi I/O di basso livello.

Tutti i sistemi di runtime dei linguaggi forniscono strumenti di livello superiore per l'esecuzione di I/O. (printf scanf di C, encapsulazione orientata agli oggetti di Java)

2. Rivisitazione della standard io Java

La libreria di I/O standard di Java è un'astrazione orientata agli oggetti. Basata su un'implementazione di livello inferiore di metodi locali, non dobbiamo preoccuparci dell'implementazione di livello inferiore. InputStream\OutputStream (flusso di byte): trasmette un byte alla volta. Reader\Writer (flusso di caratteri): un carattere alla volta.

3.Introduzione a NIO

nio è l'acronimo di javaNewIO, una nuova api fornita in JDK1.4. Le caratteristiche promosse ufficialmente da Sun sono le seguenti:

–Fornisce supporto di cache per tutti i tipi primitivi (Buffer).

–Soluzione di codifica e decodifica del set di caratteri.

–Channel: una nuova astrazione di I/O originale.

–Supporta l'interfaccia di accesso ai file di mappatura della memoria e ai file con lock.

–Fornisce I/O di rete ad alta scalabilità non bloccante (non-bloking).

Questo articolo si concentrerà su queste caratteristiche per l'apprendimento e la presentazione.

4.Buffer&Chanel

Channel e buffer sono due tipi di astrazione fondamentali del NIO.

Buffer:

–È un blocco di memoria contiguo.

–È un punto di transito per la lettura o scrittura dei dati NIO.

Channel:

–Sorgente o destinazione dei dati

–Interfaccia unica per fornire dati al buffer o leggere dati dal buffer, l'unico punto di accesso per l'oggetto buffer.

–Supporto I/O asincrono

Esempio 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";
		// 获取源文件和目标文件的输入输出流 
		FileInputStream fin = new FileInputStream(infile);
		FileOutputStream fout = new FileOutputStream(outfile);
		// 获取输入输出通道 
		FileChannel fcin = fin.getChannel();
		FileChannel fcout = fout.getChannel();
		// 创建缓冲区 
		ByteBuffer buffer = ByteBuffer.allocate(1024);
		while (true) {
			// clear方法重设缓冲区,使它可以接受读入的数据 
			buffer.clear();
			// Legge i dati dal canale di input nel buffer 
			int r = fcin.read(buffer);
			// Il metodo read restituisce il numero di byte letti, può essere zero, se il canale ha raggiunto la fine dello stream, restituisce -1 
			if (r == -1) {
				break;
			}
			// Il metodo flip permette al buffer di scrivere i nuovi dati letti in un altro canale 
			buffer.flip();
			// Scrive i dati dal canale di output nel buffer 
			fcout.write(buffer);
		}
	}
}

La struttura interna del buffer è la seguente (copiata dal materiale):

Figura 2: Struttura interna del buffer

Un buffer è controllato principalmente dai tre variabili position, limit, capacity per il processo di lettura e scrittura. Il significato di queste tre variabili è illustrato nella seguente tabella:

Parametro

Modalità di scrittura    

Modalità di lettura

position

Quantità corrente di unità di dati di scrittura.

Posizione corrente dell'unità di dati di lettura.

limit

Rappresenta il numero massimo di unità di dati che possono essere scritti e è uguale alla capacità.

Rappresenta il numero massimo di unità di dati che possono essere letti, e corrisponde alla quantità di unità di dati scritti in precedenza.

capacity

capacità del buffer

capacità del buffer

Metodi comuni di Buffer:

flip(): Converti il modo di scrittura in modalità di lettura

rewind():Ripristina position a 0, generalmente utilizzato per leggere di nuovo.

clear():Svuota il buffer, pronto per essere scritto di nuovo (position diventa 0, limit diventa capacity).

compact(): Copia i dati non letti alla testa del buffer.

mark()、reset(): mark può marcare una posizione, reset può ripristinare a quella posizione.

Tipi comuni di Buffer: ByteBuffer, MappedByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer.

Tipi comuni di channel: FileChannel, DatagramChannel (UDP), SocketChannel (TCP), ServerSocketChannel (TCP)

Ho eseguito un semplice test di prestazioni sul mio computer. Le prestazioni del mio laptop sono mediocri. (Il codice dettagliato si può trovare in allegato. Esempi nella directory nio.sample.filecopy del pacchetto). Di seguito sono riportati i dati di riferimento:

–场景1:Copy un file di 370M

–场景2: tre thread copiano contemporaneamente, ciascuna thread copia un file di 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"));
			// passo3: leggere i dati 
			ByteBuffer buffer = ByteBuffer.allocate(1024);
			// Creare un buffer di 1024 byte 
			while (channel.read(buffer) != -1) {
				buffer.flip();
				// Chiamare il metodo flip prima di operare sui byte del buffer di lettura 
				System.out.println(charset.decode(buffer));
				// Utilizzare il metodo decode di Charset per convertire i byte in una stringa 
				buffer.clear();
				// Svuotare il buffer
			}
		}
		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 bloccante

Per comprendere l'IO non bloccante, esamineremo quali sono il bloccante e il non bloccante, i principi del non bloccante e le API di core asincrone.

Cos'è il bloccante?

Un comune flusso di comunicazione di rete IO è il seguente:

Comprendiamo cos'è il bloccante attraverso questo processo di comunicazione di rete:

Nel processo sopra menzionato, se la connessione non è arrivata, allora accept si blocca e il programma deve sospendersi a questo punto, il CPU passa a eseguire altri thread.

Nel processo sopra menzionato, se i dati non sono pronti, anche read si blocca.

Caratteristiche del bloccante network IO: gestione multi-thread di più connessioni. Ogni thread ha il proprio spazio di pila e utilizza alcune unità di tempo del CPU. Ogni thread si blocca quando l'esterno non è pronto. Il risultato del blocco è che si verificano molte transizioni di contesto del processo. E molte transizioni di contesto del processo possono essere inutili. Ad esempio, supponiamo che un thread ascolti una porta e ci siano solo alcune richieste al giorno, ma il CPU deve continuamente fare tentativi di transizione di contesto per questo thread, la maggior parte dei quali si concludono con un blocco.

Cos'è il non bloccante?

C'è una metafora qui sotto:

Su un autobus pubblico che parte da A e va a B, ci sono molti punti dove le persone potrebbero scendere. Il conducente non sa quali punti avranno quali passeggeri che devono scendere e come trattare meglio coloro che devono scendere?

1. Durante il viaggio, il conducente chiede regolarmente a ogni passeggero se è arrivato al luogo di destinazione. Se qualcuno dice di sì, il conducente ferma l'autobus e i passeggeri scendono. (Simile a bloccante)

2. Ogni passeggero dice al bigliettaio il suo luogo di destinazione, poi si addormenta, il conducente interagisce solo con il bigliettaio e, raggiunta una certa fermata, il bigliettaio informa i passeggeri di scendere. (Simile a non bloccante)

Chiaramente, ogni persona che deve raggiungere un determinato obiettivo può essere considerato un thread, il conducente può essere considerato come CPU. Nel modo bloccante, ogni thread deve continuamente eseguire la scansione, lo switch di contesto, per raggiungere il risultato di trovare l'obiettivo. Nel modo non bloccante, ogni passeggero (thread) sta dormendo (in attesa), viene svegliato solo quando l'ambiente esterno è pronto, questo risveglio non blocca.

Principio non bloccante

Convertire l'intero processo in piccoli compiti, completati attraverso la collaborazione tra i compiti.

Un thread speciale gestisce tutti gli eventi di IO e si occupa della distribuzione.

Meccanismo a eventi: gli eventi attivano quando arrivano, non monitorano gli eventi in modo sincrono.

Comunicazione tra thread: i thread comunicano tra loro attraverso wait, notify e altri modi. Garantisce che ogni passaggio di contesto sia significativo. Riduce lo switch di processo inutile.

Ecco la struttura dell'IO asincrono:

Reactor è il ruolo metaforico del bigliettaio. L'iterazione di ogni thread è大概 leggere i dati, decodificare, elaborare, codificare, inviare la risposta.

API core dell'IO asincrono

Selector

La classe core dell'IO asincrono, che può rilevare eventi su uno o più canali (channel) e distribuire gli eventi.

Un singolo thread di selezione può ascoltare eventi su più canali e attivare le risposte corrispondenti basate sugli eventi, senza dover assegnare un thread per ogni channel.

SelectionKey

Contiene informazioni di stato degli eventi e il binding dei canali corrispondenti al tempo.

Sommario

Questo è tutto il contenuto dell'articolo sull'introduzione di Java, spero sia utile a tutti. Chi è interessato può continuare a consultare altre sezioni correlate del sito. Se ci sono punti insufficienti, è benvenuto a lasciare un commento. Grazie per il supporto degli amici del sito!

Dichiarazione: il contenuto di questo articolo è stato raccolto da Internet, di proprietà del rispettivo autore. Il contenuto è stato contribuito e caricato autonomamente dagli utenti di Internet, il sito web non detiene i diritti di proprietà, non è stato editato manualmente e non assume alcuna responsabilità legale. Se trovi contenuti sospetti di violazione del copyright, invia un'e-mail a notice#oldtoolbag.com (sostituisci # con @) per segnalare il problema e fornire prove pertinenti. Una volta verificata la violazione, il sito eliminerà immediatamente il contenuto sospetto.

Ti potrebbe interessare