Red de conocimiento informático - Aprendizaje de programación - ¿Cómo controlar la concurrencia multiproceso en Java?

¿Cómo controlar la concurrencia multiproceso en Java?

La comunicación entre procesos no es más que lectura y escritura de archivos, comunicación por socket o uso de memoria compartida.

Si no desea leer ni escribir archivos, utilice memoria compartida o comunicación por socket. Personalmente, me resulta más fácil usar sockets, tal vez porque estoy familiarizado con los sockets.

El siguiente es un artículo sobre cómo Java se da cuenta de la memoria compartida. Java no puede administrar la memoria. De hecho, también depende de la creación de archivos de imagen para lograrlo.

Implementación de memoria compartida en Java

La clase MappedByteBuffer proporcionada en jdk1.4 proporciona un mejor método para implementar la memoria compartida. El búfer es en realidad una imagen de memoria de un archivo de disco. Los cambios entre los dos permanecerán sincronizados, es decir, los cambios en los datos de la memoria se reflejarán inmediatamente en el archivo del disco, lo que garantizará efectivamente la realización de la memoria compartida.

La clase de canal de archivos que conecta la memoria compartida y los archivos de disco es FileChannel. La adición de esta clase sirve para que JDK unifique los métodos de acceso a dispositivos externos (archivos, interfaces de red, etc.) y mejore la seguridad del acceso multiproceso al mismo archivo. Por ejemplo, las operaciones de lectura y escritura se unifican en lectura y escritura. Aquí solo se usa para crear memoria compartida. Establece un canal entre la memoria compartida y los archivos de disco.

Para abrir un archivo y crear un canal de archivo, puede utilizar el método getChannel en la clase RandomAccessFile. Este método devolverá directamente un canal de archivo. Dado que el archivo correspondiente de este canal de archivos está configurado como un archivo de acceso aleatorio, por un lado, puede realizar operaciones de lectura y escritura. Por otro lado, su uso no destruirá el contenido del archivo de imagen (si lo usa). FileOutputStream para abrir directamente un archivo de imagen, el archivo será Si el tamaño se establece en 0, por supuesto, se perderán todos los datos). Aquí, si usa FileOutputStream y FileInputStream, lo ideal es que no pueda cumplir con los requisitos de memoria compartida, porque es mucho más difícil para estas dos clases implementar operaciones de lectura y escritura gratuitas al mismo tiempo.

El siguiente código implementa las funciones anteriores y su función es similar a la función mmap en los sistemas UNIX.

// Obtener un objeto de archivo de acceso aleatorio de solo lectura

RandomAccessFile RAFile = new RandomAccessFile(filename,"r");

// Obtener el correspondiente Canal de archivo

FileChannel fc = RAFile.getChannel();

// Obtiene el tamaño real del archivo para poder visualizarlo en la memoria compartida

int size = (int)fc.size();

// Obtiene el búfer de memoria compartida, que es de solo lectura

MappedByteBuffer mapBuf = fc.map (FileChannel.MAP_RO, 0,size);

//Obtener un objeto de archivo de acceso aleatorio de lectura y escritura

RAFile = new RandomAccessFile(filename,"rw");

/ / Obtener el canal de archivo correspondiente

fc = RAFile.getChannel();

// Obtener el tamaño real del archivo para que la imagen pueda compartirse Memoria

size = (int)fc.size();

//Obtiene el búfer de memoria compartida, que se puede leer y escribir

mapBuf = fc.map(FileChannel.MAP_RW ,0,size);

//Obtener el mensaje de encabezado: permiso de acceso

mode = mapBuf.getInt()

Si varias aplicaciones comparten memoria con el mismo nombre de archivo, significa que estas múltiples aplicaciones comparten los mismos datos de memoria.

Estas aplicaciones pueden tener los mismos derechos de acceso a los archivos y los datos actualizados por una aplicación se actualizarán en varias aplicaciones.

Para evitar que varias aplicaciones escriban en la memoria compartida al mismo tiempo, puede agregar un indicador de operación de escritura a la información del encabezado de la memoria compartida. La información básica en el encabezado de la memoria compartida es al menos:

int Longitud; // La longitud de la memoria compartida.

int mode; //El modo de acceso actual de esta memoria compartida.

La información del encabezado de la memoria compartida es la información privada de la clase. Cuando varias aplicaciones pueden realizar operaciones de escritura en la misma memoria compartida, al iniciar y finalizar la operación de escritura, es necesario llamar al siguiente método. :

public boolean StartWrite()

{

if(mode == 0) { // La bandera es 0, lo que significa que se puede escribir

mode = 1; // Establece el indicador en 1, lo que significa que otras aplicaciones no pueden escribir en la memoria compartida

mapBuf.flip(); .putInt(mode); // Escribe la información del encabezado de dicha memoria compartida

return true;

}

else {

return false; // Indica que una aplicación ya está escribiendo en la *memoria compartida y esta aplicación no puede escribir en la *memoria compartida

}

}

public boolean StopWrite()

{

mode = 0; // Liberar permiso de escritura

mapBuf.flip(); mapBuf.putInt(mode); // Escribe la información del encabezado de la memoria compartida

return true;

}

Proporcionado aquí El archivo de clase mmap.java encapsula el Interfaz básica de memoria compartida. Los lectores pueden usar esta clase para expandirla a una clase con todas las funciones que necesiten.

Si la aplicación que realiza la operación de escritura finaliza de forma anormal, la memoria compartida del archivo de imagen ya no podrá realizar operaciones de escritura. Para que el indicador de prohibición de operación de escritura se borre automáticamente después de que la aplicación finalice de manera anormal, se debe informar a la aplicación en ejecución de la aplicación que sale. En aplicaciones multiproceso, puede utilizar métodos de sincronización para lograr tales efectos, pero en procesos múltiples, la sincronización no funciona. Hay muchas técnicas que se pueden utilizar en este método. Aquí solo describimos una posible implementación: usar el bloqueo de archivos. Al escribir una aplicación de memoria compartida para obtener permiso de escritura para una memoria compartida, además de juzgar el indicador de permiso de escritura de la información del encabezado, también debe juzgar si se puede obtener un archivo de bloqueo temporal, incluso si se puede obtener. es El indicador de permiso de escritura de la información del encabezado es 1 (arriba). El permiso de escritura también se puede habilitar. De hecho, esto indica que la aplicación con permiso de escritura se cerró de manera anormal. Este código es el siguiente:

<. p>// Abra un archivo temporal, tenga en cuenta que los nombres de archivo de la misma memoria compartida deben ser los mismos. Puede agregar el sufijo ".lock" al nombre del archivo compartido.

RandomAccessFile fis = new RandomAccessFile("shm.lock","rw");

//Obtener el canal del archivo

FileChannel lockfc = fis.getChannel ( );

// Obtiene el bloqueo exclusivo del archivo. Este método no causa bloqueo y regresa inmediatamente

FileLock Flock = lockfc.tryLock();

<. p>// Si está vacío, significa que una aplicación ya tiene el bloqueo

if(flock == null) {

...//No se pueden realizar operaciones de escritura

}

else {

...//Puede realizar operaciones de escritura

}

Este bloqueo salir automáticamente después de que la aplicación sale de forma anormal. Liberar, eso es exactamente lo que se necesita aquí.