English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
1.Concepto básico
IO es el proceso de copia de datos entre la memoria principal y los dispositivos externos (disco duro, terminal y red, etc.). IO es la implementación de la funcionalidad de nivel inferior del sistema operativo, el nivel inferior mediante I/La instrucción O se completa.
Todos los sistemas de tiempo de ejecución de lenguaje proporcionan la ejecución de I/Herramientas de nivel más alto. (c de printfscanf, java de encapsulación orientada a objetos)
2.Resumen de Java standard io
La biblioteca de IO estándar de Java es una abstracción orientada a objetos de IO. Basada en la implementación subyacente de métodos locales, no necesitamos preocuparnos por la implementación subyacente. InputStream\OutputStream (flujo de bytes): transmite un byte a la vez. Reader\Writer (flujo de caracteres): un carácter a la vez.
3.Resumen de nio
NIO es la abreviatura de javaNewIO, en jdk1.4Nuevas API proporcionadas. Las características promovidas por el Sun oficial son las siguientes:
–Proporciona soporte de (Buffer) caché para todos los tipos de datos primarios.
–Solución de codificación y decodificación de conjunto de caracteres.
–Canal: un nuevo tipo de I/O/Abstracción O.
–Soporta interfaces de acceso a archivos con bloqueo y mapeo de archivos en memoria.
–Proporciona acceso a archivos con múltiples rutas (non-I/O no bloqueante) I/O con alta escalabilidad/O。
Este artículo se centrará en el aprendizaje e introducción de estas características.
4.Buffer&Chanel
Canal y buffer son dos tipos de abstracción de datos básicos en NIO.
Buffer:
–Es un bloque de memoria contigua.
–Es el medio de tránsito de lectura o escritura de datos NIO.
Canal:
–Fuente de datos o destino de datos
–Interfaz única del objeto buffer para proporcionar datos o leer datos del buffer.
–I/O asíncrono/O soporte
例子 1:CopyFile.java:
paquete 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"; // Obtener los flujos de entrada y salida de los archivos de origen y destino FileInputStream fin = new FileInputStream(infile); FileOutputStream fout = new FileOutputStream(outfile); // Obtener canales de entrada y salida FileChannel fcin = fin.getChannel(); FileChannel fcout = fout.getChannel(); // Crear buffer ByteBuffer buffer = ByteBuffer.allocate(1024); while (true) { // El método clear restablece el buffer, permitiéndole recibir datos de lectura buffer.clear(); // Lee los datos desde el canal de entrada al buffer int r = fcin.read(buffer); // El método read devuelve la cantidad de bytes leídos, puede ser cero, si el canal ha alcanzado el final del flujo, entonces devuelve-1 if (r == -1) { break; } // El método flip permite que el buffer escriba nuevos datos en otro canal buffer.flip(); // Escribe los datos desde el canal de salida al buffer fcout.write(buffer); } } }
La estructura interna del buffer es la siguiente (la imagen se copia de los materiales):
Gráfico2Estructura interna del buffer
Un buffer se controla principalmente por tres variables: position, limit y capacity, durante el proceso de lectura y escritura. El significado de estas tres variables se puede ver en la siguiente tabla:
Parámetros |
Modo de escritura |
Modo de lectura |
position |
La cantidad actual de unidades de datos de escritura. |
La posición actual de la unidad de datos de lectura. |
limit |
Representa la cantidad máxima de unidades de datos que se pueden escribir y es igual a la capacidad. |
Representa la cantidad máxima de unidades de datos que se pueden leer, y es consistente con la cantidad de unidades de datos escritas anteriormente. |
capacity |
capacidad del buffer |
capacidad del buffer |
Métodos comunes de Buffer:
flip(): Convierte el modo de escritura en modo de lectura
rewind(): Restablece position a 0, generalmente utilizado para la lectura repetida.
clear(): Limpia el buffer, preparándose para ser escrito nuevamente (position se convierte en 0, limit se convierte en capacidad).
compact(): Copia los datos no leídos al principio del buffer.
mark()、reset(): mark puede marcar una posición, reset puede restablecer a esa posición.
Tipos comunes de Buffer: ByteBuffer, MappedByteBuffer, CharBuffer, DoubleBuffer, FloatBuffer, IntBuffer, LongBuffer, ShortBuffer.
Tipos comunes de channel: FileChannel, DatagramChannel (UDP), SocketChannel (TCP), ServerSocketChannel (TCP)
Se realizó una prueba de rendimiento simple en esta máquina. La capacidad de mi portátil es generalmente decente. (El código específico se puede ver en el archivo adjunto. Véase el ejemplo en el paquete nio.sample.filecopy). A continuación se presentan los datos de referencia:
–场景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:leer datos ByteBuffer buffer = ByteBuffer.allocate(1024); // Crear1024Búfer de bytes while (channel.read(buffer) != -1) { buffer.flip(); // Llamar al método flip antes de operar con bytes en el búfer de lectura. System.out.println(charset.decode(buffer)); // Usar el método decode de Charset para convertir bytes en una cadena buffer.clear(); // Vaciar el búfer } } 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 no bloqueante
Acerca del IO no bloqueante, se entenderá desde lo que es bloqueante, lo que es no bloqueante, el principio no bloqueante y las API de núcleo asíncrono.
¿Qué es bloqueante?
Un flujo de comunicación de IO de red común es el siguiente:
Entendamos qué es bloqueante a partir de este proceso de comunicación de red:
En el proceso mencionado anteriormente, si la conexión no ha llegado, entonces accept se bloqueará y el programa aquí se tendrá que suspender, el CPU pasará a ejecutar otros hilos.
En el proceso mencionado anteriormente, si los datos no están listos, read también se bloqueará.
Características del IO de red bloqueante: manejo de múltiples conexiones por múltiples hilos. Cada hilo tiene su propio espacio de pila y consume algo de tiempo de CPU. Cada hilo se bloquea cuando el exterior no está listo. El resultado del bloqueo es que se produce una gran cantidad de cambios de contexto de proceso. Y la mayoría de los cambios de contexto de proceso pueden ser inútiles. Por ejemplo, supongamos que un hilo escucha en un puerto, puede haber solo algunas solicitudes entrantes al día, pero este cpu tiene que hacer cambios de contexto continuamente para este hilo, la mayoría de los cambios terminan en bloqueo.
¿Qué es no bloqueante?
Aquí hay una metáfora:
En un autobús público que va de A a B, hay muchos puntos donde las personas pueden bajarse. El conductor no sabe cuáles son estos puntos ni quiénes se bajarán, ¿cómo manejar mejor a las personas que necesitan bajarse?
1.El conductor pregunta en el proceso si cada pasajero ha llegado a su destino, si alguien dice que sí, el conductor para y los pasajeros bajan. (similar a bloqueante)
2.Cada persona le dice al cajero de boleto su destino, luego se duerme, el conductor solo interactúa con el cajero y, en algún punto, el cajero notifica a los pasajeros que bajen. (similar a no bloqueante)
Claramente, cada persona que llega a un destino puede considerarse un hilo, y el conductor puede considerarse la CPU. En el modo bloqueante, cada hilo necesita rastrear continuamente, cambiar de contexto, para alcanzar el destino. Y en el modo no bloqueante, cada pasajero (hilo) está durmiendo (dormir), solo se despierta cuando el entorno externo está realmente listo, y este despertar no bloqueará.
Principio no bloqueante
Cambie todo el proceso en pequeñas tareas y complete la colaboración entre tareas.
Un hilo especial se utiliza para manejar todos los eventos de IO y se encarga de la distribución.
Mecanismo de eventos: se activa cuando ocurre un evento, en lugar de monitorear eventos de manera síncrona.
Comunicación entre hilos: las hilos se comunican a través de wait, notify y otros métodos. Asegura que cada cambio de contexto sea significativo y reduzca las transiciones de proceso innecesarias.
A continuación se muestra la estructura de IO asincrónico:
Reactor es el papel de vendedor de boletos mencionado anteriormente. El flujo de procesamiento de cada hilo es aproximadamente leer datos, decodificar, procesar, codificar y enviar la respuesta.
API nuclear de IO asincrónico
Selector
La clase nuclear de IO asincrónico, que puede detectar eventos en un o varios canales (canal) y distribuirlos.
Se puede escuchar eventos en múltiples canales con una sola hilo de selección y activar la respuesta correspondiente basada en el evento, sin necesidad de asignar un hilo para cada canal.
SelectionKey
Incluye información sobre el estado del evento y el enlace correspondiente al canal correspondiente.
Resumen
Esto es todo el contenido sobre el artículo básico de Java en este artículo, espero que sea útil para todos. Los amigos interesados pueden continuar consultando otros temas relacionados en este sitio, y son bienvenidos a dejar comentarios si hay deficiencias. Agradecemos el apoyo de los amigos a este sitio!
Declaración: El contenido de este artículo se obtiene de la red, y los derechos de autor pertenecen al propietario original. El contenido es contribuido y subido por los usuarios de Internet. Este sitio no posee los derechos de propiedad, no ha sido editado por humanos y no asume responsabilidad alguna por las responsabilidades legales. Si encuentra contenido sospechoso de copyright, por favor envíe un correo electrónico a: notice#oldtoolbag.com (al enviar un correo electrónico, reemplace # con @) para denunciar, y proporcione evidencia relevante. Una vez confirmado, este sitio eliminará inmediatamente el contenido sospechoso de infracción.