Red de conocimiento informático - Material del sitio web - Ejemplos de programación multiproceso

Ejemplos de programación multiproceso

¡Hilo! Expresé mi entendimiento de manera muy simple. Quizás sea útil decírtelo.

Comprender la diferencia entre subprocesos y procesos puede entenderse primero como subprocesos que forman procesos.

En primer lugar, esta clase es

Generalmente hay dos formas de crear instancias: una es heredar el hilo y la otra es implementar la excusa ejecutable.

Sus métodos incluyen iniciar una operación de suspensión, esperar a que se detenga, etc.

Primero, la diferencia entre proceso y aplicación

Un proceso es un concepto definido originalmente en Unix y otros sistemas operativos multiusuario y multitarea para representar aplicaciones en un entorno de memoria. unidad básica de ejecución. Tomando el sistema operativo Unix como ejemplo, el proceso es un componente básico del entorno del sistema operativo Unix y la unidad básica de asignación de recursos del sistema. Casi todo el trabajo de gestión de usuarios y asignación de recursos en el sistema operativo Unix se logra mediante el control de los procesos de aplicación por parte del sistema operativo.

Los programas fuente escritos en C, C++, Java y otros lenguajes son compilados en archivos ejecutables por el compilador correspondiente y enviados al procesador de la computadora para su ejecución. En este momento, la aplicación en estado ejecutable se denomina proceso. Desde la perspectiva del usuario, un proceso es el proceso de ejecución de una aplicación. Desde el núcleo del sistema operativo, un proceso representa la unidad básica de recursos, como la memoria y los intervalos de tiempo de CPU asignados por el sistema operativo, y es el entorno operativo proporcionado para ejecutar programas. La diferencia entre un proceso y una aplicación es que una aplicación se almacena como un archivo estático en un espacio de almacenamiento como el disco duro del sistema informático, mientras que un proceso es una entidad de gestión de recursos del sistema mantenida por el sistema operativo en condiciones dinámicas. Las principales características de los procesos de aplicación en un entorno multitarea incluyen:

●El proceso tiene un punto de entrada inicial de la unidad de memoria durante la ejecución y siempre tiene un espacio de direcciones de memoria independiente durante su supervivencia;

●El estado de vida del proceso incluye creación, listo, en ejecución, bloqueo, muerte y otros tipos;

●Las instrucciones de ejecución enviadas por el proceso de aplicación a la CPU tienen diferentes formas. del proceso se puede dividir en estado de usuario y estado de núcleo. Los procesos en modo de usuario ejecutan instrucciones de la aplicación y los procesos de aplicación en modo kernel ejecutan instrucciones del sistema operativo.

Durante el proceso de inicio del sistema operativo Unix, el sistema crea automáticamente procesos del sistema como swapper e init para administrar los recursos de memoria y programar procesos de usuario. En un entorno Unix, los procesos creados por el sistema operativo y los procesos creados por las aplicaciones tienen identificadores de proceso únicos (PID).

En segundo lugar, la diferencia entre un proceso y un hilo de Java

Durante la ejecución de una aplicación, existe una dirección de punto de entrada inicial del espacio de memoria y una secuencia de ejecución de código durante la ejecución del programa y una dirección de punto de salida de memoria que marca el final del proceso. En cada momento durante la ejecución del proceso, hay una instrucción de procesador única correspondiente a la dirección de una ubicación de memoria.

Un hilo definido en el lenguaje Java también incluye una dirección de punto de entrada a la memoria, una dirección de punto de salida y una secuencia de código que se puede ejecutar secuencialmente. Sin embargo, la diferencia importante entre un proceso y un subproceso es que un subproceso no se puede ejecutar de forma independiente y debe ejecutarse en un proceso de aplicación activo. Por lo tanto, un subproceso se puede definir como un flujo de código secuencial concurrente dentro de un programa.

El sistema operativo Unix y el sistema operativo Microsoft Windows admiten la ejecución simultánea de múltiples usuarios y procesos, mientras que el lenguaje Java admite la ejecución simultánea de múltiples subprocesos de ejecución dentro de un proceso de aplicación. La importancia del subproceso múltiple es que se pueden ejecutar varias unidades lógicas de una aplicación al mismo tiempo. Pero el subproceso múltiple no significa que se estén ejecutando múltiples procesos de usuario y el sistema operativo no trata cada subproceso como un proceso independiente para asignar recursos independientes del sistema. Un proceso puede crear sus procesos secundarios, que tienen código ejecutable y espacio de memoria de datos diferentes a los del proceso principal. Dentro del proceso utilizado para representar la aplicación, varios subprocesos * * * disfrutan del espacio de memoria de datos, pero mantienen cada subproceso con una pila de ejecución independiente y un contexto de ejecución del programa.

Basándonos en las diferencias anteriores, los subprocesos también pueden denominarse procesos ligeros (LWP). Diferentes subprocesos permiten la colaboración de tareas y el intercambio de datos, lo que lo hace muy económico en términos de consumo de recursos del sistema informático.

Los subprocesos requieren soporte del sistema operativo y no todos los tipos de computadoras admiten aplicaciones multiproceso. El lenguaje de programación Java combina soporte de subprocesos y entorno de ejecución del lenguaje para brindar la capacidad de ejecutar múltiples tareas al mismo tiempo.

Al igual que poner la ropa en la lavadora, se lavará automáticamente, se pondrá arroz en la olla arrocera y luego se cocinará. Los platos están listos, el arroz está listo y la ropa está lavada.

Cabe señalar que el uso de subprocesos múltiples en una aplicación no aumenta las capacidades de procesamiento de datos de la CPU. Solo bajo una computadora con múltiples CPU o una arquitectura informática de red, después de dividir el programa Java en múltiples subprocesos de ejecución concurrentes, iniciar varios subprocesos para que se ejecuten al mismo tiempo y permitir que se ejecuten diferentes subprocesos en máquinas virtuales Java basadas en diferentes procesadores, puede aplicación se mejore la eficiencia de ejecución del programa.

Además, las aplicaciones multiproceso son útiles si la aplicación debe esperar un recurso con un rendimiento de datos relativamente bajo, como una conexión de red o una conexión de base de datos. Las aplicaciones basadas en Internet requieren subprocesos múltiples. Por ejemplo, cuando se desarrolla una aplicación del lado del servidor que admite una gran cantidad de clientes, la aplicación se puede crear en forma de subprocesos múltiples para responder a las solicitudes de conexión del cliente, de modo que cada usuario conectado pueda tener un subproceso de conexión de cliente exclusivo. De esta manera, los usuarios sienten que el servidor sólo atiende a los propios usuarios conectados, acortando así el tiempo de respuesta del cliente del servidor.

3. Método de programación multiproceso en lenguaje Java

El método para implementar aplicaciones multiproceso en lenguaje Java es muy sencillo. Dependiendo de la herencia de subprocesos múltiples o del objeto de implementación; hay dos formas de editar la aplicación: una es que el objeto en ejecución concurrente de la aplicación herede directamente la clase de subproceso Java y la otra es definir un objeto de ejecución concurrente para implementar la interfaz Runnable.

Método de programación multiproceso para heredar la clase de subproceso

La clase de subproceso es una clase definida en JDK para controlar objetos de subproceso, que encapsula los métodos para el control de subprocesos. Consulte el siguiente código de muestra:

[código]//Consumer.java

Importar Java.util.*;

Clase Consumer extends Thread

{

int nTime

String strConsumer

Consumidor público (int nTime, String strConsumer)

{

this.nTime = nTime

this.strConsumer = strConsumer

}

Ejecución de vacío público()

{

while(true)

{

Probar

{

System.out.println(" Nombre del consumidor: "+strConsumer+" \ n ");

thread. sleep(nTime);

}

Capturar (Excepción e)

{

e . printstacktrace();

}

}

}

estático público vacío principal( String args[])

{

Consumidor aConsumidor = nuevo consumidor(1000, "un Consumidor");

un consumidor .start (); p>

Consumidor bConsumidor = nuevo consumidor (2000, "b Consumidor");

b consumidor .

Consumidor cConsumidor =Nuevo Consumidor(3000, "c Consumer");

cconsumer.start();

}

} [/code]

Como se puede ver en la En el código de programa anterior, el consumidor subterráneo de ejecución multiproceso hereda la clase de subproceso Thread en el lenguaje Java y crea tres instancias de objetos de consumidor en el método principal. Cuando se llama al método de inicio de una instancia de objeto, se llama automáticamente al método de ejecución definido en la clase de consumidor para iniciar el hilo del objeto. El resultado de la ejecución del hilo es imprimir el contenido de la variable miembro de cadena strConsumer en la instancia del objeto cada nTime.

Se puede concluir que el método de programación multiproceso para heredar la clase de subproceso es permitir que la clase de aplicación herede la clase de subproceso e implementar el procesamiento concurrente en el método de ejecución de esta clase.

Método de programación multiproceso para implementar una interfaz ejecutable

Otro método proporcionado por el lenguaje Java para implementar aplicaciones multiproceso es que el objeto multiproceso implementa la interfaz Runnable y define el inicio. en esta clase El método de ejecución del hilo. La ventaja de esta definición es que los objetos de aplicación multiproceso pueden heredar otros objetos en lugar de tener que heredar clases de subprocesos, lo que puede aumentar la lógica de las definiciones de clases.

El código marco de una aplicación multiproceso que implementa la interfaz Runnable es el siguiente:

//Consumer.java

Importar Java util.

El usuario de la clase implementa Runnable

{

… …

Consumidor público (int nTime, String strConsumer){… …

public void run(){… …}

Static public void main(String args[])

{

Subproceso aConsumer = new Thread(new Consumer(1000, "a Consumer");

a consumer . start();

//Subprocesos que ejecutan otras instancias de objetos

/ /… …

}

}

Como se puede ver en el código anterior, esta clase implementa la interfaz Runnable y define el método de ejecución en esta clase. La diferencia importante entre la implementación de aplicaciones multiproceso y aquellas que heredan la clase thread son los diferentes métodos para iniciar objetos multiproceso. En el código anterior, la instancia de la clase Thread se crea creando una instancia del objeto Thread y tomando. el objeto de la aplicación como parámetro.

Cuarto, sincronización entre subprocesos

Múltiples subprocesos de aplicaciones Java * * * comparten los recursos de datos del mismo proceso. Los subprocesos de usuario pueden operar simultáneamente. Acceda a contenido confidencial. El concepto de sincronización de subprocesos se define en Java para lograr un mantenimiento consistente de los recursos compartidos. A continuación se utiliza el método de control de sincronización entre subprocesos en el sistema de facturación de comunicaciones móviles desarrollado recientemente por el autor. Proceso de implementación de sincronización multiproceso en lenguaje Java

En ausencia de una estrategia de control de sincronización multiproceso, el código de marco definido por la clase de cuenta del cliente es el siguiente:

Cuenta de registro de clase pública

{

Saldo flotante

//Método de pago del cliente

Depósito público no válido (tarifas flotantes){ saldo+ = fFees;}

// Método de facturación de llamadas

public void retract(float fFees){ f balance-= fFees;}

… …

}

Los lectores pueden pensar que el código del programa anterior puede satisfacer completamente las necesidades reales del sistema de facturación. De hecho, el programa es confiable en un entorno de un solo subproceso. ¿Se ejecutan varios procesos simultáneamente? Mientras realiza el pago, el centro de servicio al cliente utiliza un dispositivo de comunicación móvil para realizar una llamada. Cuando un cliente llama, el sistema de facturación inicia el proceso de facturación y el personal del centro de servicio también envía el proceso de facturación para que se ejecute. Los lectores pueden ver que si esto sucede, la cuenta del cliente no se toma en serio.

¿Cómo solucionar este problema? Muy simple, agregue la palabra clave sincronizada a la definición del método de la clase RegisterAccount para identificar el método sincronizado. De esta manera, durante la ejecución del método de sincronización, el * * * recurso compartido involucrado en el método (en el código anterior, es la variable miembro fBalance) será * * * bloqueado para garantizar que solo el método pueda acceder * * * recursos compartidos, otros subprocesos pueden acceder a estos * * * recursos compartidos hasta que el subproceso del método termine de ejecutarse y abra el * * * bloqueo compartido.

Cuando el bloqueo de acceso no está abierto, se bloquean otros subprocesos que acceden al recurso.

La definición de la clase RegisterAccount después del control de la política de sincronización de subprocesos se muestra en el siguiente código:

Clase pública Registrar cuenta

{

FBalance flotante

Retracción de anulación pública sincronizada (float fFees){ f balance+= fFees;}

Retracción de anulación pública sincronizada (float fFees){ f balance-= fFees;}

… …

}

Desde el formulario de código definido por el mecanismo de sincronización de subprocesos, podemos ver que después de que el método de acceso al recurso * * * accede al palabra clave de atributo (pública) Se agrega la palabra clave de definición de sincronización sincronizada, de modo que cuando el método de sincronización accede a * * * recursos, * * se adjuntan bloqueos de acceso a estos recursos confidenciales para controlar la exclusividad de los recursos durante la ejecución del método y lograr la coherencia de los datos del sistema de la aplicación. recursos y mantenimiento.

Verbo (abreviatura de verbo) Gestión de subprocesos Java

Control de estado de subprocesos

Lo que debe quedar claro aquí es que no importa cómo heredes la clase Thread o implementar la interfaz Runnable Para realizar la capacidad de subprocesos múltiples de una aplicación, debe definir un método de ejecución en esta clase para completar la función real. Este método de ejecución se denomina cuerpo de hilo. Según los diferentes estados del cuerpo del hilo en la memoria del sistema informático, los hilos se pueden dividir en creación, listo, ejecución, suspensión, suspensión y muerte. Las características de los subprocesos bajo estos tipos de estado de subproceso son:

Estado de creación: cuando se usa la nueva palabra clave para crear una instancia de objeto de subproceso, solo existe como una instancia de objeto y la JVM no asigna recursos de ejecución de subprocesos. como intervalos de tiempo de CPU;

Estado listo: llame al método de inicio en el hilo que creó el estado para cambiar el estado del hilo al estado listo. En este momento, el subproceso ha obtenido otros recursos del sistema excepto el tiempo de CPU y solo está esperando que el programador de subprocesos de la JVM programe el subproceso de acuerdo con la prioridad del subproceso, para que el subproceso tenga la oportunidad de obtener el intervalo de tiempo de la CPU.

Estado de suspensión: mientras el subproceso se está ejecutando, puede llamar al método de suspensión, especificar el tiempo de suspensión del subproceso en los parámetros del método y convertir el estado del subproceso al estado de suspensión. En este momento, el hilo deja de ejecutarse dentro del tiempo de suspensión especificado sin liberar los recursos ocupados. Cuando se acaba el tiempo, el programador de subprocesos JVM programa y administra el subproceso nuevamente.

Estado de suspensión: puede cambiar el estado de un hilo al estado suspendido llamando al método de suspensión. En este momento, el subproceso liberará todos los recursos ocupados y la JVM los programará en un espacio de almacenamiento temporal hasta que la aplicación llame al método de reanudación para reanudar la operación del subproceso.

Estado muerto: cuando el cuerpo del hilo termina de ejecutarse o se llama al método de parada del objeto del hilo, el hilo dejará de ejecutarse y la JVM recuperará los recursos ocupados por el hilo.

La clase de subproceso Java define los métodos correspondientes para controlar y gestionar el estado del subproceso en la aplicación.

Programación de subprocesos

La importancia de la llamada de subprocesos es que la JVM debe coordinar múltiples subprocesos en ejecución a nivel del sistema para evitar fallas del sistema de aplicaciones o fallas causadas por múltiples subprocesos que compiten por recursos limitados.

Para distinguir la importancia de los subprocesos para el sistema operativo y los usuarios, Java define una política de prioridad de subprocesos. Java divide las prioridades de los subprocesos en 10 niveles, representados por números entre 1 y 10. Cuanto mayor sea el número, mayor será el nivel del hilo. En consecuencia, las variables miembro MIN_PRIORITY, MAX_PRIORITY y NORMAL_PRIORITY se definen en la clase de subproceso, que representan las prioridades mínima, máxima y normal del subproceso, respectivamente. Los niveles de prioridad son 1, 10 y 5 respectivamente. Cuando se crea un objeto de subproceso, su prioridad de subproceso predeterminada es 5.

Para controlar la estrategia de ejecución de los subprocesos, Java define un programador de subprocesos para monitorear todos los subprocesos en estado listo en el sistema. El programador de subprocesos decide qué subproceso colocar en el procesador según la prioridad del subproceso. Cuando varios subprocesos están en estado listo, el subproceso con mayor prioridad se ejecutará antes que el subproceso con menor prioridad.

El programador de subprocesos también utiliza una estrategia de preferencia para programar la ejecución del subproceso, es decir, cuando un subproceso con una prioridad más alta ingresa al estado listo durante la ejecución del subproceso actual, el subproceso con una prioridad más alta se programa inmediatamente para su ejecución. A todos los subprocesos con la misma prioridad se les asignan intervalos de tiempo de CPU mediante rotación.

Es muy sencillo establecer la prioridad de los subprocesos en su aplicación. Después de crear un objeto de subproceso, puede llamar al método setPriority del objeto de subproceso para cambiar la prioridad de ejecución del subproceso, o puede llamar al método getPriority para obtener la prioridad del subproceso actual.

Un hilo especial en Java es un hilo de bajo nivel llamado hilo demonio. Este hilo tiene la prioridad más baja y se utiliza para proporcionar servicios a otros objetos e hilos del sistema. La forma de configurar un hilo de usuario como demonio es llamar al método setDaemon del objeto hilo antes de crearlo. Un ejemplo típico de subproceso de demonio es el subproceso de reciclaje automático de recursos del sistema en la JVM. Siempre se ejecuta en el estado subyacente y se utiliza para monitorear y administrar los recursos reciclables en el sistema en tiempo real.

Gestión de grupos de subprocesos

Java define un objeto ThreadGroup en un sistema operativo multiproceso para implementar una gestión de grupos centralizada de subprocesos basada en funciones específicas. Cada hilo creado por el usuario pertenece a un grupo de hilos, que se puede especificar al crear el hilo, o el grupo de hilos no se puede especificar para que el hilo esté en el grupo de hilos predeterminado. Sin embargo, una vez que un hilo se une a un grupo de hilos, el hilo permanecerá en el grupo de hilos hasta que muera y el grupo de hilos al que pertenece el hilo no se puede cambiar a mitad de camino.

Cuando se ejecuta una aplicación Java, la JVM crea un grupo de subprocesos llamado main. A menos que se especifique por separado, todos los subprocesos creados en esta aplicación pertenecen al grupo de subprocesos principal. Se pueden crear grupos de subprocesos con otros nombres en el grupo de subprocesos principal, y se pueden agregar otros subprocesos al grupo de subprocesos, y así sucesivamente, formando una relación de herencia y gestión de árbol entre subprocesos y grupos de subprocesos.

Al igual que los subprocesos, los objetos del grupo de subprocesos se pueden programar, gestionar y priorizar. En el proceso de gestión de grupos de subprocesos, todos los subprocesos que se unen al grupo de subprocesos se consideran objetos unificados.

Resumen del verbo intransitivo:

Este artículo analiza y explica la naturaleza de los subprocesos en la plataforma Java y la estrategia multiproceso de las aplicaciones.

A diferencia de otros entornos de sistemas operativos, los subprocesos en el entorno operativo Java son similares a los subprocesos en entornos de sistemas operativos multiusuario y multitarea, pero existen diferencias obvias entre procesos y subprocesos en sus métodos de ejecución y creación. .

En el entorno del sistema operativo Unix, la aplicación puede utilizar la función fork para crear un proceso hijo, pero el proceso hijo y el proceso de aplicación tienen espacios de direcciones, recursos del sistema y unidades de ejecución de código independientes. el proceso está controlado por la operación Finalización del sistema, lo que hace que la comunicación y la coordinación de subprocesos entre los procesos de la aplicación sean relativamente complejas. El subproceso múltiple en aplicaciones Java significa que varios ejecutores de código paralelos comparten los mismos recursos del sistema de aplicación, y los métodos de comunicación y coordinación entre subprocesos son relativamente simples.

Se puede decir que el soporte del lenguaje Java para las capacidades de subprocesos múltiples de las aplicaciones ha mejorado las ventajas de Java como lenguaje de programación de red, permitiendo el acceso simultáneo de múltiples clientes en sistemas de aplicaciones distribuidas y mejorando la eficiencia de la respuesta. del servidor. Se sentó una base sólida.

La programación de hilos en Java es muy sencilla. Pero a veces verás algún uso incorrecto de los hilos. Aquí hay algunas cuestiones a las que debes prestar atención.

1. Constancia de los objetos sincronizados

Todos los objetos java son referencias.

Para las variables y parámetros locales, los tipos de datos básicos como int, float, double y boolean en Java están todos en la pila. Estos tipos básicos no se pueden sincronizar; los objetos en Java (el objeto raíz es el objeto) están en el montón y las referencias a objetos están en la pila.

El objeto de sincronización en Java es en realidad la "dirección del objeto" a la que hace referencia la referencia de sincronización.

Cabe señalar que los objetos de sincronización nunca deben reasignarse. Por ejemplo.

La clase A implementa Runnable{

Bloqueo de objeto = nuevo objeto();

Ejecución no válida(){

Para (.. .){

Sincronización (bloqueo){

//Hacer algo

...

lock = new Object();

}

}

}

Este código de sincronización en la función de ejecución en realidad no tiene sentido. Debido a que cada bloqueo proporciona una nueva referencia al objeto reasignado, cada hilo se sincroniza con la nueva referencia.

Quizás te preguntes cómo puedes dar un ejemplo así. Como he visto código como este, al objeto de sincronización se le asigna un nuevo valor en otras funciones.

Este tipo de problema es difícil de resolver.

Por lo tanto, los objetos de sincronización normalmente deben declararse finales.

Bloqueo de objeto final = new object();

Usar el patrón de diseño Singleton para obtener objetos de sincronización también es una buena opción.

2. Cómo colocar * * *Disfruta de los datos

Hay dos formas de implementar subprocesos, una es heredar la clase Thread y la otra es implementar la interfaz Runnable.

El ejemplo anterior utiliza el método de implementación de la interfaz Runnable. Este artículo recomienda este enfoque.

Primero coloque los datos que deben compartirse en una clase que implemente la interfaz Runnable y luego pase instancias de esta clase a múltiples constructores de subprocesos. De esta manera, todos los subprocesos recién creados tienen una instancia ejecutable y comparten los mismos datos.

Si adopta el método de heredar la clase Thread, debe utilizar miembros estáticos estáticos. Si * * * disfruta de más datos, se requiere una gran cantidad de miembros estáticos, lo que hace que la estructura de datos del programa sea confusa y difícil de expandir. Esta situación debe evitarse siempre que sea posible.

Escribe un código multiproceso para manejar un problema un poco más complejo. Conocerás las ventajas y desventajas de estos dos métodos una vez que los pruebes.

3. Granularidad de sincronización

Cuanto menor sea la granularidad de sincronización de subprocesos, mejor, es decir, más pequeño será el bloque de código de sincronización de subprocesos. Intente evitar declarar métodos con modificadores de sincronización. Intente utilizar el método sincronizado (unObjeto). Si no desea introducir un nuevo objeto de sincronización, utilice el método sincronizado (este). Además, cuanto más pequeños sean los bloques de código sincronizados, mejor.

4. Notificación entre hilos

Aquí se utiliza la palabra "notificación" en lugar de la palabra "comunicación" para evitar ampliar el significado.

La notificación entre subprocesos se logra mediante los métodos wait() y notify() o notifyAll() del objeto.

El siguiente es un ejemplo para ilustrar cómo funciona:

Supongamos que hay dos subprocesos, A y B. * * * Ambos tienen un objeto de sincronización, lock.

1. Primero, el subproceso A obtiene el objeto de sincronización de bloqueo a través de la sincronización (bloqueo) y luego llama a la función lock.wait () para abandonar el objeto de sincronización de bloqueo. El subproceso A deja de ejecutarse y entra en espera. cola.

2. El subproceso B obtiene el objeto de sincronización de bloqueo abandonado por el subproceso A a través de la sincronización (bloqueo), completa cierto procesamiento y luego llama a lock.notify() o lock.notifyAll() para notificar al subproceso A en el cola de espera.

3. El hilo A sale de la cola de espera, ingresa a la cola de listo y espera la programación.

4. El subproceso B continúa procesándose y, después del bloque sincronizado (bloqueo), abandona el objeto de sincronización de bloqueo.

5. El subproceso A obtiene el objeto de sincronización de bloqueo y continúa ejecutándose.

El código de muestra es el siguiente:

La clase pública SharedResource implementa Runnable{

Bloqueo de objeto = nuevo objeto();

Público ejecución no válida (){

//Obtiene el nombre del hilo actual.

nombre del hilo de cadena = hilo actual(). getNombre();

if( "A ".

Igual a (nombre del hilo)){

Sincronizado(bloqueo){ // El hilo A obtiene el objeto de sincronización de bloqueo a través de Sincronizado(bloqueo).

Pruebe {

System.out.println("A abandona el bloqueo.");

lock wait(); Llamar al bloqueo. La función wait() abandona el objeto de sincronización de bloqueo.

//El hilo A deja de ejecutarse y entra en la cola de espera.

}catch(InterruptedException e){

}

// El subproceso A continúa ejecutándose después de volver a adquirir el objeto de sincronización de bloqueo.

System.out.println("A adquiere nuevamente el bloqueo y continúa ejecutándose.");

} //La sincronización finaliza (bloqueo)

}

}

p>

if( "B ". Igual a (nombre del hilo)){

Sincronizado (bloqueo){//El hilo B obtiene el objeto de sincronización de bloqueo abandonado por el subproceso A a través de Sincronizado (bloqueo).

System.out.println("B obtuvo el bloqueo.");

lock . notify(); //Notifica al hilo A en la cola de espera para ingresar a la cola lista y esperar programación.

//El subproceso B continúa procesándose y abandona el objeto de sincronización de bloqueo después del bloque sincronizado (bloqueo).

System.out.println("B abandona el bloqueo.");

} //La sincronización finaliza (bloqueo)

boolean has lock = thread .holds lock(lock); //Compruebe si B posee el objeto de sincronización de bloqueo.

System.out.println("¿B tiene un candado?-"+tiene candado); // false.

}

}

}

Clase pública TestMain{

Público static void main(){

recurso ejecutable = nuevo recurso compartido();

Subproceso A = nuevo subproceso(recurso, "A");

a.start();

p>

//Fuerza que el hilo principal deje de ejecutarse para que el hilo A pueda comenzar a ejecutarse.

Prueba {

thread . sleep(500

}catch(InterruptedException e){

}

Subproceso B = nuevo subproceso(recurso, "B");

b

}

}

5. Objetos de sincronización entre clases

Para problemas simples, puede colocar todo el código de sincronización que accede a * * recursos en una clase.

Pero para problemas complejos, necesitamos dividir el problema en varias partes para manejarlo, y se necesitan varias clases diferentes para manejar el problema. En este momento, necesitas * * * disfrutar de objetos de sincronización de diferentes niveles. Por ejemplo, los objetos de sincronización se comparten entre productores y consumidores, y entre lectores y escritores.

¿Cómo * * * disfrutar de diferentes tipos de objetos de sincronización? Hay varias formas de lograr esto:

(1) El método mencionado anteriormente usa miembros estáticos (o usa el modo Singleton).

(2) Se pasa a través de parámetros para pasar la sincronización. objetos a diferentes clases.

(3) Aproveche la "atomicidad" de las constantes de cadena.

Para el tercer método, aquí tienes una explicación. En términos generales, las constantes de cadena en el código del programa son únicas después de la compilación, es decir, no habrá dos constantes de cadena idénticas en la memoria.

(Por lo general, los programas en lenguaje C++ y C tienen las mismas características después de la compilación).

Por ejemplo, tenemos el siguiente código.

Cadena A = " átomo

Cadena B = " átomo

Tenemos razones para creer que A y B apuntan a la misma constante de cadena. Es decir, A==B = B.

Tenga en cuenta que el código que declara variables de cadena no cumple con las reglas anteriores.

String C=new string("atom");

String D=new string("atom");

Aquí c y d Las declaraciones son todas las declaraciones de variables de cadena, entonces, c! = D.

Con la comprensión anterior, podemos usar constantes de cadena como objetos de sincronización.

Por ejemplo, si usamos sincronizado("MyLock"), "mi bloqueo". Espere() y "MyLock". Código Notify () en diferentes clases, podemos lograr la sincronización de subprocesos entre diferentes clases.

Este artículo no recomienda encarecidamente este uso, solo explica que existe tal método.

Este artículo recomienda el segundo método, (2) pasar objetos de sincronización a diferentes clases mediante el paso de parámetros.

Esta es tu web

/Article/java/xc/