Mutex en Java
Dans le monde de l’informatique, l’exclusion mutuelle ou Mutex est connue comme une propriété de contrôle de la concurrence. Chaque ordinateur utilise la plus petite séquence d’instructions programmées appelée thread. À un moment donné, l’ordinateur fonctionne sur un seul thread. Plongeons-nous dans d’autres aspects pour une meilleure compréhension.
Threading et multithreading
Le processeur fonctionne sur les threads pour le multitâche. Chaque processus fonctionne en passant constamment d’un fil à l’autre à une vitesse très rapide. Par exemple, lorsque nous regardons une vidéo, l’audio de la vidéo est sur un fil différent et l’image sur un autre. Le basculement constant entre ces deux éléments est très rapide et est connu sous le nom de multithreading.
Les threads en Java
La création d’un thread en Java se fait en étendant une classe et en implémentant une interface. Le multithreading est une fonctionnalité Java qui permet l’exécution simultanée de deux ou plusieurs parties d’un programme afin de maximiser l’efficacité du processeur. Un thread est un composant d’un tel programme. Les threads sont donc des processus légers au sein des processus.
Mutex
Deux threads ou plus peuvent avoir besoin d’accéder simultanément à une ressource partagée dans un programme multithread, ce qui entraîne un comportement inattendu. Les structures de données, les périphériques d’entrée-sortie, les fichiers et les connexions réseau sont des exemples de ressources partagées.
C’est ce qu’on appelle une condition de course. La section clé du programme est la partie du programme qui accède à la ressource partagée. En conséquence, nous devons synchroniser l’accès à la partie critique pour éviter une condition de concurrence.
Le type de synchroniseur le plus basique est un mutex (ou exclusion mutuelle), qui garantit qu’un seul thread peut exécuter la zone essentielle d’un programme informatique à la fois. Il est implémenté par une classe appelée semaphore
.
Un thread obtient le mutex, puis accède à la section cruciale et libère enfin le mutex pour accéder à une région critique. Pendant ce temps, tous les autres threads sont bloqués jusqu’à ce que le mutex soit libéré. Un thread peut entrer dans la section critique dès qu’il sort de la zone critique.
Pour mutex, il existe deux méthodes de verrouillage et de déverrouillage. Ils sont respectivement appelés acquire()
et release()
. Maintenant, regardez l’exemple ci-dessous.
En savoir plus sur Mutex ici.
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
}
Dans l’exemple ci-dessus, nous avons créé deux objets Mutex portant le nom de mutex
et mutex1
. Nous utiliserons mutex1
pour contrôler le basculement entre deux threads. La raison de la création de la LinkedList est d’avoir un historique des discussions. Maintenant, ajoutons deux threads dans le code ci-dessus. Deux threads avec le nom de Producer
et 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();
}
}
}
Explication
Le code ci-dessus est également explicite, mais cette explication résoudra la confusion.
Dans le fil Producer
Lorsque vous exécutez le programme ci-dessus, il crée un fil de discussion producer
. À l’intérieur de ce fil, il y a une boucle while
qui s’exécutera indéfiniment. La chaîne threadName
sert uniquement à afficher l’exécution du thread. L’objet mutex
acquerra le verrou pour que le thread consommateur soit fonctionnel. (L’objectif principal de Mutex, obtenir le contrôle de la concurrence).
Après cela, le fil producer
devient fonctionnel. Ensuite, nous devons libérer ce fil pour la production. Dans le thread producer
, nous allons libérer mutex1
, l’objet chargé de gérer le basculement entre consumer
et producer
. A la sortie, les consommateurs commenceront à consommer, c’est-à-dire que le fil consumer
sera fonctionnel.
Dans le fil Consumer
Juste après être entré dans le fil consumer
, nous avons acquis mutex1
pour arrêter la production pendant la consommation. Comme vous pouvez le constater, nous avons créé trois consommateurs sous les noms C1
, C2
et C3
. Afin de permettre à un seul consommateur d’être fonctionnel à la fois, nous avons également acquis mutex
.
Après cela, C1
deviendra fonctionnel, tandis que C2
et C3
seront acquis. Une fois terminé, mutex
sera à nouveau libéré, permettant à l’autre consommateur d’être fonctionnel.
C’est ainsi que fonctionne le mutex en Java. Après avoir exécuté le programme ci-dessus. Il affichera en permanence le nombre actuel de threads producer
utilisés et le nom du consumer
qui l’utilise.
La taille continuera d’augmenter au fur et à mesure que le programme s’exécute.
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