10

Sémaphores

Un sémaphore compte le nombre de fois qu'une ressource limitée est en cours d'utilisation. Quand un composant a besoin d'une ressource partagée spécifique, il essaie de l'acquérir auprès du sémaphore qui la gère. Si la ressource n'est pas disponible, le fil d'exécution du demandeur est automatiquement bloqué. Dès qu'un autre composant libère la ressource, un des fils d'exécution en attente est réveillé et reprend le contrôle.

  1. public class Semaphore {
  2.     private int count;
  3.  
  4.     public Semaphore(int n) {
  5.         this.count = n;
  6.     }
  7.  
  8.     public synchronized void acquire() {
  9.         while (count == 0) {
  10.             try {
  11.                 wait();
  12.             }
  13.             catch (InterruptedException e) {
  14.             }
  15.         }
  16.         count--;
  17.     }
  18.  
  19.     public synchronized void release() {
  20.         count++;
  21.         notify();
  22.     }
  23. }

Une instance de Semaphore est toujours initialisée avec le nombre total d'unités disponibles de la ressource qu'elle gère. La méthode acquire bloque le fil d'exécution tant que le compteur de la ressource est à zéro. Si la ressource est disponible, le compteur est décrémenté de un et l'exécution se poursuit normalement. La méthode release incrémente le compteur de la ressource de un et réveille tous les fils d'exécution en attente avec un appel à notify. L'un d'eux reprendra la main, reviendra dans la boucle de la méthode acquire et pourra continuer son exécution après avoir réservé la ressource.

Notez que acquire et release sont synchronisées afin de prévenir toute interférence sur le compteur.

Pour tester Semaphore, nous allons créer une série de fils d'exécution qui essayeront tous et en même temps d'utiliser une ressource limitée pour un temps donné.

  1. public class SemaphoreTest {
  2.     private Semaphore sema = new Semaphore(2);
  3.  
  4.     public void go() {
  5.         for (int i = 0; i < 7; i++)
  6.             (new Thread(new Consumer(i + 1, sema))).start();
  7.     }
  8.  
  9.     private class Consumer implements Runnable {
  10.         private Semaphore sema;
  11.  
  12.         private int id;
  13.  
  14.         Consumer(int id, Semaphore sema) {
  15.             this.sema = sema;
  16.             this.id = id;
  17.         }
  18.  
  19.         public void run() {
  20.             System.out.println(id + " - " + "Acquiring resource");
  21.             sema.acquire();
  22.             System.out.println(id + " - " + "Resource is locked");
  23.             try {
  24.                 Thread.sleep((long) (Math.random() * 1000));
  25.             }
  26.             catch (InterruptedException e) {
  27.             }
  28.             System.out.println(id + " - " + "Releasing resource");
  29.             sema.release();
  30.         }
  31.     }
  32.  
  33.     public static void main(String args[]) {
  34.         (new SemaphoreTest()).go();
  35.     }
  36. }

Le programme crée un Semaphore qui autorise l'utilisation simultanée de deux unités d'une ressource, puis lance l'exécution en parallèle de sept instances de Consumer qui ont toutes accès au sémaphore. Un Consumer affiche un message avant d'essayer d'acquérir la ressource, appelle acquire, affiche un message dès que la ressource est disponible, fait quelque chose pendant un moment, affiche un dernier message avant de libérer la ressource et appelle release.

Notez que le programme ne décide pas quand il peut prendre la ressource et continuer son exécution. Toute la logique est dans Semaphore.

$ javac SemaphoreTest.java
$ java SemaphoreTest
1 - Acquiring resource
1 - Resource is locked
2 - Acquiring resource
2 - Resource is locked
3 - Acquiring resource
4 - Acquiring resource
...
2 - Releasing resource
3 - Resource is locked
3 - Releasing resource
4 - Resource is locked
4 - Releasing resource
1 - Releasing resource
5 - Resource is locked
...

L'ordre d'exécution des instances concurrentes de Consumer peut varier.

Commentaires

Votre commentaire :
[p] [b] [i] [u] [s] [quote] [pre] [br] [code] [url] [email] strip aide 2000

Entrez un maximum de 2000 caractères.
Améliorez la présentation de votre texte avec les balises de formatage suivantes :
[p]paragraphe[/p], [b]gras[/b], [i]italique[/i], [u]souligné[/u], [s]barré[/s], [quote]citation[/quote], [pre]tel quel[/pre], [br]à la ligne,
[url]http://www.izend.org[/url], [url=http://www.izend.org]site[/url], [email]izend@izend.org[/email], [email=izend@izend.org]izend[/email],
[code]commande[/code], [code=langage]code source en c, java, php, html, javascript, xml, css, sql, bash, dos, make, etc.[/code].