Executors et thread pools

Groupage et exécution des threads

Ce site ne sera plus alimenté de contenu après août 2014. Tous les nouveaux articles seront redigés pour www.waitingforcode.com

L'exécution des plusieurs threads peut être facilitée par de nombreux outils mis à disposition dans le package java.util.concurrent. L'un d'eux est Executor. Au début de cette article on le présentera d'un point de vue théorique. Plus loin on verra comment le mettre en place.

Executors

Grâce aux executors on peut concevoir des systèmes basés sur l'exécution de plusieurs Threads. Il s'agit d'un sorte de gestionnaires qui organisent l'exécution des tâches. Grâce à eux on a la possibilité d'un meilleur contrôle sur les traitements. Il est possible de spécifier la taille maximale d'un thread pool (liste des threads), interrompre l'exécution d'un traitement ou de préciser le temps de vie d'un Thread. Voici comment cela se présente dans le code :

import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.TimeUnit;
 
public class ThreadPool {
    private ArrayBlockingQueue<Runnable> queue = new ArrayBlockingQueue<Runnable>(1);
  
    public static void main(String[] args) {
        ThreadPool t = new ThreadPool();    
    }

    public ThreadPool() {
        ThreadPoolExecutor ex = new ExtendedExecutor(1, 1, 5, TimeUnit.SECONDS, queue, new ExtendedHandler());
        ex.allowCoreThreadTimeOut(true);
        for (int i = 0; i < 10; i++) {
          Runnable r = new Numbers(""+i);
          ex.execute(r);
        }
    }
}

class ExtendedExecutor extends ThreadPoolExecutor {
    public ExtendedExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime,TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
    }
  
    protected void beforeExecute(Thread t, Runnable r) {
        System.out.println("Tasks in the pool : " + getActiveCount());
    }
  
    protected void afterExecute(Runnable r, Throwable t) {
        System.out.println("Completed tasks : " + getCompletedTaskCount());    
    }
}

class ExtendedHandler implements RejectedExecutionHandler {
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
        executor.execute(r);
    }
}

class Numbers implements Runnable {
    private String number = "";
  
    public Numbers(String n) {
        number = n;
    }
  
    public void run() {
        System.out.println("Running " + number);
    }

    public String toString() {
        return number;
    }
}

Au tout début on initialise la classe de l'executor qui va lancer les traitements. Le nombre maximal des Threads dans la queue est 1. Si l'exécution d'une tâche échoue (pas d'espace libre dans la queue), la méthode rejectedExecution() de la classe ExtendedHandler sera automatiquement appelée. Cette fonction essayera tout de suite de se ratrapper pour exécuter l'action planifiée. Dans la classe ExtendedExecutor on remarque la présence des deux méthodes (hooks) : beforeExecute() et afterExecute(). La première est appelée avant le lancement d'une nouvelle tâche. L'autre est évoquée après ce lancement.

Bartosz KONIECZNY Concurrence

Une question ? Une remarque ?

*

*

Moi

Développeur d'applications Internet et journaliste passionné par l'adjectif français. Un aigle polonais orienté vers la progression, volant très haut et écoutant du zouk après les matches du foot français.

Vous appréciez mon travail ?

Pour contribuer au développement de ce site, ou pour remercier pour des articles rédigés, vous pouvez faire un don.

Un conseil MySQL

Comment sommer les champs du type TIME ?

La requête suivante devrait être utile :
SELECT SEC_TO_TIME(SUM(TIME_TO_SEC(maColonne))) AS somme FROM nomTableau;