Sémaphore dans un pool de Thread avec Spring 2.5




 

 
Dans ce post, je vais vous montrer comment utiliser les sémaphores dans un pool de Thread Java avec Spring 2.5. Une fois de plus , c’est d’une simplicité extrême.

 

Prérequis

– Connaissance Java;
– Maven installé, si ce n’est pas fait reportez vous à l’article installer Maven sous Linux pour les OS Linux ou installer Maven sous Windows pour les OS Windows;
– Eclipse installé.
– Avoir lu l’article Gérer un pool de thread avec Spring 2.5

 

Pourquoi les sémaphores ?

On cherche avec un pool de Thread à limiter les ressources d’une machine utilisées par une application multithreadée.

L’utilisation des sémaphores va nous permettre ici d’éviter le rejet de tâches du fait d’un problème de capacité du pool.
Mais il est toujours possible de paramétrer le pool de manière à éviter les rejets.
Cependant, une augmentation de la capacité exige des ressources supplémentaires.

 
Les 3 paramètres corePoolSize, maxPoolSize et queueCapacity tel que le mode de fonctionnement est expliqué dans l’article Gérer un pool de thread avec Spring 2.5, montre que dans une configuration donnée certaines de vos tâches peuvent simplement être rejetées par le pool et du coup ne pas être prises en compte par votre application.

Bien entendu, les exceptions peuvent prévenir ce problème, mais pas le résoudre de manière simple. C’est ici que les sémaphores ont leur utilité.

Enfin sachez que sans sémaphore, votre application ne s’écroulera pas, par contre des tâches pourraient ne pas être exécutées.

 

Comment notre application va fonctionner avec les sémaphores ?

Il faut considérer les sémaphores comme des tickets relatifs à des places.

Ainsi le pool de thread distribuera les tickets aux tâches pour qu’elles puissent prendre place dans le pool.

Lorsqu’il n’y a plus de places dans le pool, la distribution des tickets/sémaphores s’interrompt.

La distribution reprend dès qu’une place dans le pool se libère. Les tâches en attente de place dans le pool patientent jusqu’à ce qu’une place se libère et que le pool leur distribue un ticket.

 

Notre projet MAVEN

Nous faisons simple en reprenant le projet de l’article Gérer un pool de thread avec Spring 2.5. Nous ferons évoluer ce code en y intégrant les sémaphores.

 

L’exemple

 

Le code source de la tâche

La tâche est représentée par une classe. Pour que cette classe puisse être exécutée via un thread, elle doit implémenter l’interface Runnable. Cette interface oblige à implémenter une méthode void run() qui comporte le code exécuté par le thread.
Pour notre exemple, notre tâche effectuera une pause dont la durée aléatoire variera entre 5 et 15 secondes.
Elle affichera une information à l’entrée de la méthode Run, à sa sortie, et son temps de pause.

Le constructeur a évolué puisqu’il prend un paramètre supplémentaire qui est un sémaphore.
Le sémaphore est fourni par le lanceur de tâches.
La tâche libère le sémaphore à la fin de son exécution.

package thread;
 
import java.util.Random;
import java.util.concurrent.Semaphore;
 
public class TestTask implements Runnable
{
  public Integer threadNumber;
  private Semaphore semaphoreTest;
 
  public TestTask(int i, Semaphore s)
  {
    this.threadNumber = i;
    this.semaphoreTest = s;
  }

  @Override
  public void run()
  {
    System.out.println("Thread start " + threadNumber);

    // Génération d'un nombre aléatoire entre
    // 5s et 15s pour le temps de pause du Thread
    Random r = new Random();
    int valeur = 5000 + r.nextInt(15000 - 5000);
    System.out.println("Thread pause " + threadNumber + " " + valeur);

    try 
    {
      Thread.sleep(valeur);
    } catch (InterruptedException e) 
    {
      e.printStackTrace();
    }

    // libération du sémaphore
    semaphoreTest.release();

    System.out.println("Thread stop" + threadNumber);
  }
 
  public void setThreadNumber(Integer threadNumber)
  {
    this.threadNumber = threadNumber;
  }
}

 

Le code source du lanceur de tâches

Le lanceur est chargé d’assigner les tâches au pool qui les gèrera conformément à la configuration qui lui est imposée. Ceci se fait par le biais d’une classe java composée de la classe ThreadPoolTaskExecutor, le pool de thread.

Le lanceur de tâches initialise le nombre total de tickets/sémaphores disponibles par le biais de la variable semaphoreNumber.
Le lanceur de tâches distribue les tickets/sémaphores par le biais de la méthode semaphoreTest.acquire(). La méthode acquire() est bloquante, ainsi lorsque le nombre (semaphoreNumber) de tickets/sémaphores distribué est atteint, le lanceur de tâches est bloqué jusqu’à ce qu’un sémaphore soit libéré.
Un sémaphore est libéré lorsqu’une tâche en exécution arrive à son terme (semaphoreTest.release()). Ce sémaphore est alors être redistribué par le pool pour une autre tâche.

package thread;
 
import java.util.concurrent.Semaphore;

import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
 
public class LauncherTestTask
{
  private ThreadPoolTaskExecutor taskExecutor;
  private int semaphoreNumber;
  private Semaphore semaphoreTest;
  
  public void launch()
  {
    semaphoreTest = new Semaphore(semaphoreNumber);	
    taskExecutor.setWaitForTasksToCompleteOnShutdown(true);
    for (int i=1 ; i<30 ; i++)
    {
      try 
      {
        // acquisition d'un sémaphore
        semaphoreTest.acquire();
      } 
      catch (InterruptedException e1) 
      {
        e1.printStackTrace();
      }
	  
      try
      {
        taskExecutor.execute(new TestTask(i, semaphoreTest) );
      } catch (Exception e)
      {
        System.out.println("T" + i + " rejeté par le Pool");
      }
    }
    taskExecutor.shutdown();
  }
 
  public void setTaskExecutor(ThreadPoolTaskExecutor taskExecutor)
  {
    this.taskExecutor = taskExecutor;
  }
  
  public void setSemaphoreNumber(int number) 
  {
	  this.semaphoreNumber = number;
  }
}

 

Le fichier applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
       xmlns:context="http://www.springframework.org/schema/context" 
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd"
       default-autowire="byName">

  <bean id="taskExecutor"
    class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="5" />
    <property name="maxPoolSize" value="5" />
    <property name="queueCapacity" value="10" />
  </bean>

  <bean id="launcherTestTask" class="thread.LauncherTestTask">
    <property name="taskExecutor">
      <ref bean="taskExecutor" />
    </property>
    <property name="semaphoreNumber" value="10"/>
  </bean>

</beans>

 

Lancement de l’exemple

Grâce au fichier applicationContext.xml, Spring va nous permettre de récupérer une instance du lanceur, puis d’en invoquer la méthode launch.
Le chargement du fichier applicationContext.xml se fait par le biais de la classe ClassPathXmlApplicationContext, dont le constructeur prend en paramètre le nom du fichier de contexte (applicationContext.xml dans le cas présent).
La récupération de l’instance de la classe dont nous avons besoin se fait par la biais de la méthode getBean qui prend en paramètre le nom du bean (bean id) défini dans le fichier de contexte.

Le code source:

package Thread;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Run
{
  public static void main(String[] args) throws InterruptedException 
  {
    ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
    LauncherTestTask launcherTestTask = (LauncherTestTask)ctx.getBean("launcherTestTask");
    launcherTestTask.launch();
  }
}

 
[important]Vous savez maintenant utiliser des sémaphores dans un pool de Thread en Java, faites en bon usage.
Les commentaires sont les bienvenus.[/important]

 

Posté dans javaTaggé developpement java, java thread, pool de thread, pool de thread java, sémaphore thread, thread, thread java, thread pool, thread pool java  |  Laisser un commentaire

Répondre

*