Mutex en Java
En el mundo de la informática, la exclusión mutua o Mutex se conoce como una propiedad del control de concurrencia. Cada computadora trabaja con la secuencia más pequeña de instrucción programada conocida como hilo. En un momento, la computadora funciona en un solo hilo. Profundicemos en algunos aspectos más para una mejor comprensión.
Subprocesos y subprocesos múltiples
La CPU funciona en subprocesos para realizar múltiples tareas. Cada proceso funciona cambiando constantemente de un hilo a otro a una velocidad muy rápida. Por ejemplo, cuando miramos un video, el audio del video está en un hilo diferente y la imagen está en otro diferente. El cambio constante entre estos dos es muy rápido y se conoce como multiproceso.
Hilos en Java
La creación de un hilo en Java se realiza ampliando una clase e implementando una interfaz. El subproceso múltiple es una característica de Java que permite la ejecución de dos o más partes de un programa simultáneamente para maximizar la eficiencia de la CPU. Un hilo es un componente de dicho programa. Los subprocesos son, por tanto, procesos ligeros dentro de los procesos.
Mutex
Es posible que dos o más subprocesos necesiten acceder a un recurso compartido simultáneamente en un programa multiproceso, lo que da como resultado un comportamiento inesperado. Las estructuras de datos, los dispositivos de entrada y salida, los archivos y las conexiones de red son ejemplos de recursos compartidos.
Se denomina condición de carrera. La sección clave del programa es la parte del programa que accede al recurso compartido. Como resultado, debemos sincronizar el acceso a la parte crítica para evitar una condición de carrera.
El tipo más básico de sincronizador es un mutex (o exclusión mutua), que asegura que solo un hilo puede ejecutar el área esencial de un programa de computadora a la vez. Está implementado por una clase llamada semaphore
.
Un hilo obtiene el mutex, luego accede a la sección crucial y, por último, libera el mutex para acceder a una región crítica. Mientras tanto, todos los demás subprocesos se bloquean hasta que se libera el mutex. Un hilo puede entrar en la sección crítica tan pronto como sale del área crítica.
Para mutex, existen dos métodos para bloquear y desbloquear. Se conocen como acquire()
y release()
respectivamente. Ahora eche un vistazo al ejemplo a continuación.
Obtenga más información sobre Mutex aquí.
import java.util.LinkedList; // linked list import
import java.util.concurrent.Semaphore; // semaphore import
public class Mutex {
static LinkedList<String> WorkingQueue = new LinkedList<String>();
// track the record of works
static Semaphore mutex1 = new Semaphore(0); // creating a Semaphore To ImplementLogic
static Semaphore mutex = new Semaphore(1); // Creating A Mutex
}
En el ejemplo anterior, creamos dos objetos Mutex con el nombre de mutex
y mutex1
. Usaremos mutex1
para controlar el cambio entre dos hilos. La razón para crear la Lista Vinculada es tener un historial de subprocesos. Ahora, agreguemos dos subprocesos en el código anterior. Dos hilos con el nombre de Productor
y Consumer
.
import java.util.LinkedList; // linked list import
import java.util.concurrent.Semaphore; // semaphore import
public class Mutex {
static LinkedList<String> WorkingQueue = new LinkedList<String>();
// track the record of works
static Semaphore mutex1 = new Semaphore(0); // creating a Semaphore To ImplementLogic
static Semaphore mutex = new Semaphore(1); // Creating A Mutex
static class Producer extends Thread {
public void run() { // default run method of thread
int counter = 1;
try {
while (true) {
String threadName = Thread.currentThread().getName()
+ counter++; // counter is added to have the thread number being used
mutex.acquire(); // Acquiring Lock before Producing so the consumer cannot consume.
WorkingQueue.add(threadName);
System.out.println("Producer is prdoucing producing: " + threadName);
mutex.release(); // releasing After Production ;
mutex1.release(); // relesing lock for consumer...so consumer can consume after production
Thread.sleep(2000); // just to Reduce the Execution Speed
}
} catch (Exception e) { /*nothing */
}
}
}
static class Consumer extends Thread {
String consumerName;
public Consumer(String name) {
this.consumerName = name;
}
public void run() {
try {
while (true) {
mutex1.acquire(); /// Again Acquiring So no production while consuming
mutex.acquire(); // Acquring Other consumers lock one consume at one time
String result = "";
for (String value : WorkingQueue) {
result = value + ",";
}
System.out.println(consumerName + " consumes value: " + result
+ "Total Size working Queue Size " + WorkingQueue.size() + "\n");
mutex.release(); // releasing lock for other consumers.
}
} catch (Exception e) {
}
}
public static void main(String[] args) {
Producer producer = new Producer();
producer.start();
Consumer c1 = new Consumer("Bill Gates");
Consumer c2 = new Consumer("Jeff Bezoz");
Consumer c3 = new Consumer("Mark Zukerberg");
c1.start();
c2.start();
c3.start();
}
}
}
Explicación
El código anterior también se explica por sí mismo, pero esta explicación resolverá la confusión.
Dentro del hilo Productor
Cuando ejecute el programa anterior, creará un hilo de productor
. Dentro de ese hilo, hay un bucle while
que se ejecutará por tiempo indefinido. La cadena threadName
es solo para mostrar la ejecución del hilo. El objeto mutex
adquirirá el bloqueo para que el hilo consumidor sea funcional. (El objetivo principal de Mutex, obtener el control de la concurrencia).
Después de eso, el hilo productor
se vuelve funcional. Entonces tenemos que lanzar este hilo para producción. En el hilo productor
, liberaremos mutex1
, el objeto responsable de manejar el cambio entre consumer
y productor
. Una vez liberado, los consumidores comenzarán a consumir, es decir, el hilo consumer
será funcional.
Dentro del hilo del Consumer
Inmediatamente después de ingresar al hilo consumer
, adquirimos mutex1
para detener la producción durante el consumo. Como puede ver, hemos creado tres consumidores con los nombres C1
, C2
y C3
. Para permitir que un consumidor sea funcional a la vez, también adquirimos mutex
.
Después de eso, C1
se volverá funcional, mientras que se adquirirán C2
y C3
. Una vez finalizado, mutex
se liberará de nuevo, lo que permitirá que el otro consumidor sea funcional.
Así es como funciona mutex en Java. Después de ejecutar el programa anterior. Constantemente mostrará el número actual de hilos de productor
que se están utilizando y el nombre del consumer
que lo utiliza.
El tamaño seguirá aumentando a medida que se ejecute el programa.
Haider specializes in technical writing. He has a solid background in computer science that allows him to create engaging, original, and compelling technical tutorials. In his free time, he enjoys adding new skills to his repertoire and watching Netflix.
LinkedIn