HOWTO · Java

Ritarda di pochi secondi in Java

Scopri quando usare Thread.sleep() per una pausa bloccante e quando pianificare attività ritardate o ripetute in Java.

In questa pagina

Per una pausa semplice, usa Thread.sleep(): sospende il thread corrente per la durata richiesta. Se un’attività deve essere eseguita più tardi o ripetuta mentre il thread chiamante continua a lavorare, usa un ScheduledExecutorService. Gli esempi seguenti illustrano entrambe le opzioni, la gestione delle interruzioni e la pulizia delle attività pianificate.
Mettere in pausa l’esecuzione appartiene al gruppo delle utilità del Tutorial Java, con le altre ricette quotidiane su date, numeri casuali e console.

Usare Thread.sleep() per una semplice pausa bloccante

Thread.sleep() accetta una durata in millisecondi e sospende il thread che lo invoca. Questo programma autonomo attende un secondo prima di stampare il messaggio. Il metodo main dichiara InterruptedException, quindi l’interruzione viene propagata al chiamante invece di essere ignorata.

public class Main {
  public static void main(String[] args) throws InterruptedException {
    Thread.sleep(1000);
    System.out.println("One second has passed.");
  }
}

In un metodo che non può propagare InterruptedException al chiamante, intercetta l’eccezione e ripristina lo stato di interruzione con Thread.currentThread().interrupt(). Il codice di livello superiore potrà così rilevare la richiesta di annullamento e gestirla secondo la policy dell’applicazione. La pausa sospende solo il thread corrente, non gli altri thread del processo.

Usare TimeUnit.sleep() per indicare l’unità di tempo

TimeUnit.SECONDS.sleep(2) esprime direttamente una pausa di due secondi. Blocca comunque il thread chiamante e può essere interrotto, quindi applica la stessa policy di gestione delle interruzioni usata con Thread.sleep().

import java.util.concurrent.TimeUnit;

public class Main {
  public static void main(String[] args) {
    try {
      TimeUnit.SECONDS.sleep(2);
      System.out.println("Two seconds have passed.");
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      System.out.println("Pause interrupted.");
    }
  }
}

Scegli questa forma quando specificare l’unità rende la durata più chiara. TimeUnit.sleep() è un modo leggibile per esprimere un’attesa a tempo, ma non permette di mantenere disponibile il thread corrente per altre attività durante l’attesa.

Pianificare un’attività ripetuta con ScheduledExecutorService

Un ScheduledExecutorService esegue un Runnable dopo un ritardo o a intervalli regolari, lasciando libero il thread chiamante. scheduleAtFixedRate() riceve l’attività, il ritardo iniziale, il periodo e un TimeUnit. L’executor invoca il metodo run() dell’attività: run() contiene il lavoro da svolgere e non pianifica autonomamente l’attività.

Questo programma avvia un’attività dopo un secondo e ne richiede una nuova esecuzione ogni secondo. Dopo cinque secondi, un’altra attività pianificata annulla quella ripetuta e arresta l’executor. La pianificazione dipende dalle risorse disponibili durante l’esecuzione; il numero e la tempistica delle righe stampate possono quindi variare.

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

public class Main {
  public static void main(String[] args) {
    ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
    ScheduledFuture<?> task = executor.scheduleAtFixedRate(
        () -> System.out.println("Task running"), 1, 1, TimeUnit.SECONDS);
    executor.schedule(() -> {
      task.cancel(false);
      executor.shutdown();
    }, 5, TimeUnit.SECONDS);
  }
}

Conserva il ScheduledFuture restituito se potrebbe essere necessario annullare l’attività ripetuta. Arresta l’executor quando l’applicazione non ne ha più bisogno; altrimenti il suo thread di lavoro potrebbe mantenere attivo il processo. Per un’unica attività ritardata, usa schedule() invece di una pianificazione ripetuta.

Usare un riferimento a metodo con ScheduledExecutorService

Se un metodo esistente senza argomenti rappresenta l’attività da eseguire, puoi fornirlo come Runnable tramite un riferimento a metodo. Questo programma pianifica una singola chiamata dopo due secondi e poi arresta l’executor. L’arresto impedisce l’invio di nuove attività, lasciando però terminare quelle già in coda.

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

public class Main {
  public static void main(String[] args) {
    ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
    executor.schedule(Main::executeTask, 2, TimeUnit.SECONDS);
    executor.shutdown();
  }

  private static void executeTask() {
    System.out.println("Task running");
  }
}

Usa un metodo di pausa per un’attesa breve quando è opportuno sospendere il thread corrente. Scegli un executor pianificato quando le altre attività devono continuare o quando un’attività deve essere eseguita più tardi o ripetutamente. La pausa blocca il thread chiamante e non richiede di gestire un executor; le attività pianificate lasciano libero quel thread, ma occorre arrestare l’executor e annullare le attività ripetute quando non servono più.