HOWTO · Java
Faire un compte à rebours en Java
Cet article vous montre des méthodes pour créer un compte à rebours en Java.
Sur cette page
Un compte à rebours en Java affiche le temps restant à intervalles réguliers et s’arrête lorsqu’il arrive à son terme. Vous pouvez en créer un avec ScheduledExecutorService, Timer et TimerTask, ou avec une simple boucle utilisant Thread.sleep(). Ces exemples reposent uniquement sur la bibliothèque standard de Java et peuvent être adaptés à une sortie console ou à une interface utilisateur.
Fonctionnement d’un compte à rebours en Java
Choisissez la source de temps et le mode d’exécution en fonction de votre application. Une tâche planifiée s’exécute périodiquement sans bloquer le thread qui l’a démarrée. Une boucle avec Thread.sleep() est plus facile à suivre, mais bloque le thread courant entre les mises à jour. Aucune des deux API de planification ne garantit qu’un rappel sera exécuté à un instant précis : l’ordonnancement du système d’exploitation et d’autres tâches peuvent retarder une mise à jour.
Pour qu’un affichage reste synchronisé avec l’heure réelle, calculez le nombre de secondes restantes à partir d’une échéance à chaque mise à jour, au lieu de supposer que chaque rappel arrive exactement une seconde après le précédent. Les exemples ci-dessous utilisent de courts délais pour que le code reste lisible ; adaptez la valeur initiale et la période à votre application.
Créer un compte à rebours console avec ScheduledExecutorService
ScheduledExecutorService constitue un bon choix par défaut pour les tâches d’arrière-plan récurrentes. Ce programme console complet démarre à trois, affiche chaque valeur jusqu’à un, puis indique la fin du compte à rebours et arrête son exécuteur. La tâche démarre immédiatement et s’exécute une fois par seconde.
Exécutez cet exemple :
Le code et les libellés ou sorties affichés dans cette section restent en anglais.
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class Countdown {
public static void main(String[] args) {
ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor();
final int[] remaining = {3};
scheduler.scheduleAtFixedRate(() -> {
if (remaining[0] > 0) {
System.out.println(remaining[0]--);
} else {
System.out.println("Countdown complete!");
scheduler.shutdown();
}
}, 0, 1, TimeUnit.SECONDS);
}
}
Le compteur modifiable n’est utilisé que par l’unique tâche planifiée ; AtomicInteger n’est donc pas nécessaire ici. La vérification de fin a lieu après l’affichage de la dernière valeur, ce qui évite d’afficher un nombre négatif. Si plusieurs threads peuvent accéder à la tâche, utilisez une gestion d’état sûre en environnement concurrent. Appelez shutdown() lorsqu’il n’y a plus de travail à effectuer ; pour permettre un arrêt déclenché de l’extérieur, conservez le ScheduledFuture<?> renvoyé par l’appel de planification et annulez-le.
Les blocs d’exemple conservent leurs chaînes d’affichage en anglais. Ils affichent les valeurs du compte à rebours, puis le message de fin prévu par le code.
Afficher un compte à rebours avec Timer et TimerTask
Timer planifie une TimerTask après un délai initial, puis à une période fixe. L’exemple console suivant suit la même séquence de fin : son minuteur est annulé lorsque le compte à rebours se termine, afin que son thread ne maintienne pas l’application en vie.
Le code et les libellés ou sorties affichés dans cette section restent en anglais.
import java.util.Timer;
import java.util.TimerTask;
public class TimerCountdown {
public static void main(String[] args) {
Timer timer = new Timer();
final int[] remaining = {3};
timer.scheduleAtFixedRate(new TimerTask() {
@Override
public void run() {
if (remaining[0] > 0) {
System.out.println(remaining[0]--);
} else {
System.out.println("Countdown complete!");
timer.cancel();
}
}
}, 0, 1000);
}
}
Pour mettre à jour un libellé Swing, n’appelez pas directement setText depuis TimerTask.run() : la tâche s’exécute sur le thread d’arrière-plan du minuteur. Publiez la mise à jour de l’interface sur le thread de distribution des événements Swing avec SwingUtilities.invokeLater(() -> label.setText(...)). Arrêtez le minuteur lorsque la fenêtre se ferme ou que le compte à rebours est annulé. Timer utilise un seul thread d’arrière-plan ; une tâche lente peut donc retarder les autres tâches planifiées sur ce même minuteur.
Les chaînes d’affichage présentes dans les blocs d’exemple restent en anglais, car leur code est conservé à l’identique.
Créer un compte à rebours bloquant avec Thread.sleep()
Une boucle avec Thread.sleep() convient à une petite tâche en ligne de commande lorsque le blocage du thread courant est acceptable. sleep met ce thread en pause pendant une durée approximativement égale à celle demandée ; cette méthode ne garantit pas une temporisation exacte.
Le code et les libellés ou sorties affichés dans cette section restent en anglais.
public class BlockingCountdown {
public static void main(String[] args) {
for (int remaining = 3; remaining > 0; remaining--) {
System.out.println(remaining);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Countdown interrupted.");
return;
}
}
System.out.println("Countdown complete!");
}
}
En cas d’interruption, le code rétablit l’état d’interruption du thread et se termine au lieu d’ignorer le signal d’annulation. N’exécutez pas cette boucle sur le thread de distribution des événements Swing : la pause empêcherait ce thread de traiter les entrées et les événements de rafraîchissement. Pour une interface réactive, utilisez un planificateur ou un minuteur Swing.
Choisir un minuteur et gérer la fin sans risque
Utilisez ScheduledExecutorService pour planifier des tâches en arrière-plan, gérer explicitement leur annulation ou contrôler le cycle de vie d’un exécuteur. Timer peut convenir à une petite tâche récurrente sur un seul thread, mais son unique thread de travail fait qu’une tâche lente retarde les suivantes. Choisissez Thread.sleep() pour une simple pause séquentielle lorsque le blocage est voulu. Avec Swing, planifiez les mises à jour de l’affichage sur le thread de distribution des événements ou utilisez le minuteur propre à Swing pour les rappels destinés à l’interface.
Définissez le comportement de fin avant la planification : décidez quelles valeurs afficher, quelle action effectuer lorsque le compteur atteint zéro et comment gérer l’annulation. Arrêtez l’exécuteur ou annulez le minuteur lorsque le compte à rebours se termine ou que son propriétaire est fermé. Si la tâche est interrompue, préservez ce signal ou arrêtez-vous proprement. Pour afficher précisément le temps restant, recalculez-le à partir d’une échéance, car les rappels périodiques peuvent dériver ou arriver en retard.