Java - Planificateur de Thread

Bonjour à tous, futurs sorciers Java ! Aujourd'hui, nous allons entreprendre un voyage passionnant dans le monde de la planification des threads Java. Ne vous inquiétez pas si vous êtes nouveau en programmation – je serai votre guide ami, et nous aborderons ce sujet étape par étape. Alors, prenez vos baguettes virtuelles (claviers), et plongeons-y !

Java - Thread Scheduler

Qu'est-ce que la Planification des Threads ?

Avant de plonger dans les détails, comprenons ce qu'est la planification des threads. Imaginez que vous êtes un maître de cérémonie de cirque (cela serait le temps d'exécution Java), et que vous avez plusieurs artistes (threads) en attente pour montrer leurs numéros. Votre travail consiste à décider quel artiste va sur scène et pendant combien de temps. C'est essentiellement ce que fait la planification des threads dans Java – elle gère plusieurs threads et décide lequel doit s'exécuter et quand.

Pourquoi avons-nous besoin de Planification des Threads ?

Vous pourriez vous demander, "Pourquoi ne pouvons-nous pas laisser tous les threads s'exécuter quand ils veulent ?" Eh bien, imaginez si tous les artistes de cirque essayaient de performer en même temps – ce serait le chaos ! La planification des threads aide à maintenir l'ordre, assure une allocation équitable des ressources et améliore la performance globale du système.

Planificateur de Thread de Java

Java a un planificateur de thread intégré qui s'occupe de cette tâche complexe pour nous. Il utilise une combinaison de planification au niveau du système d'exploitation et de ses propres algorithmes pour gérer les threads efficacement.

États des Threads

Avant de nous plonger dans la planification, examinons rapidement les différents états dans lesquels peut se trouver un thread :

  1. Nouveau
  2. Exécutable
  3. En cours d'exécution
  4. Bloqué/En attente
  5. Terminé

Le planificateur est responsable du déplacement des threads entre ces états.

Création et Planification de Threads de Base

Commençons par un exemple simple pour voir comment Java crée et planifie des threads :

public class SimpleThreadExample {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Thread 1: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});

Thread thread2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Thread 2: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});

thread1.start();
thread2.start();
}
}

Dans cet exemple, nous créons deux threads qui impriment des nombres de 0 à 4. L'appel Thread.sleep(1000) fait pause chaque thread pendant 1 seconde entre les impressions.

Lorsque vous exécutez ce programme, vous remarquerez que la sortie peut ne pas être dans un ordre alternatif parfait. C'est parce que le planificateur Java décide quand basculer entre les threads !

Priorités des Threads

Java nous permet de donner des indices au planificateur sur les threads les plus importants. Nous pouvons définir les priorités des threads à l'aide de la méthode setPriority(). Modifions notre exemple précédent :

public class ThreadPriorityExample {
public static void main(String[] args) {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Thread de Priorité Basse: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});

Thread thread2 = new Thread(() -> {
for (int i = 0; i < 5; i++) {
System.out.println("Thread de Priorité Haute: " + i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});

thread1.setPriority(Thread.MIN_PRIORITY);
thread2.setPriority(Thread.MAX_PRIORITY);

thread1.start();
thread2.start();
}
}

Dans cet exemple, nous définissons thread1 avec la priorité la plus basse et thread2 avec la priorité la plus haute. Bien que cela ne garantisse pas que thread2 s'exécutera toujours en premier ou plus souvent, cela donne au planificateur un indice qu'il devrait préférer thread2 lorsque cela est possible.

ScheduledExecutorService

Maintenant, examinons une manière plus avancée de planifier des threads à l'aide de ScheduledExecutorService. Cet outil puissant nous permet de planifier des tâches pour s'exécuter après un délai ou à des intervalles fixes.

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class ScheduledExecutorExample {
public static void main(String[] args) {
ScheduledExecutorService executor = Executors.newScheduledThreadPool(2);

Runnable task1 = () -> System.out.println("Tâche 1 exécutée à : " + System.currentTimeMillis());
Runnable task2 = () -> System.out.println("Tâche 2 exécutée à : " + System.currentTimeMillis());

executor.schedule(task1, 5, TimeUnit.SECONDS);
executor.scheduleAtFixedRate(task2, 0, 2, TimeUnit.SECONDS);

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

executor.shutdown();
}
}

Dans cet exemple :

  • Nous créons un ScheduledExecutorService avec 2 threads.
  • task1 est planifiée pour s'exécuter une fois après un délai de 5 secondes.
  • task2 est planifiée pour s'exécuter toutes les 2 secondes, en commençant immédiatement.
  • Nous laissons le programme s'exécuter pendant 10 secondes avant de fermer l'executor.

Cela montre comment nous pouvons contrôler précisément quand et combien de fois nos tâches s'exécutent.

Méthodes de ScheduledExecutorService

Voici un tableau des principales méthodes fournies par ScheduledExecutorService :

Méthode Description
schedule(Runnable, long, TimeUnit) Planifie une tâche unique pour s'exécuter après un délai spécifié
scheduleAtFixedRate(Runnable, long, long, TimeUnit) Planifie une tâche pour s'exécuter périodiquement, avec un délai fixe entre le début de chaque exécution
scheduleWithFixedDelay(Runnable, long, long, TimeUnit) Planifie une tâche pour s'exécuter périodiquement, avec un délai fixe entre la fin d'une exécution et le début de la suivante

Conclusion

Et voilà, les amis ! Nous avons traversé les bases de la planification des threads Java, de la création simple de threads à la planification avancée avec ScheduledExecutorService. Rappelez-vous, la planification des threads est comme diriger un orchestre – c'est tout une question de harmony et de timing.

À mesure que vous continuez votre aventure Java, vous découvrirez encore plus de moyens pour affiner le comportement des threads. Mais pour l'instant, félicitez-vous – vous avez fait un grand pas dans le monde de la programmation concurrente !

Continuez à pratiquer, restez curieux, et surtout, amusez-vous à coder ! Qui sait, peut-être que vous écrirez un jour la prochaine génération de planificateurs de threads Java. En attendant, bonne threading !

Credits: Image by storyset