Перейти к основному содержимому

Как отложить выполнение кода в Java

· 3 мин. чтения

1. Введение

Программы на Java довольно часто добавляют задержку или паузу в своей работе. Это может быть полезно для стимуляции задачи или для приостановки выполнения до завершения другой задачи.

В этом руководстве будут описаны два способа реализации задержек в Java.

2. Подход на основе потоков

Когда программа Java запускается, она порождает процесс , который выполняется на хост-компьютере. Этот процесс содержит как минимум один поток — основной поток , в котором выполняется программа. Кроме того, Java поддерживает многопоточность , что позволяет приложениям создавать новые потоки, работающие параллельно или асинхронно с основным потоком.

2.1. Использование Thread.sleep

Быстрый и грязный способ сделать паузу в Java — это указать текущему потоку спать в течение определенного периода времени. Это можно сделать с помощью Thread.sleep(миллисекунды) :

try {
Thread.sleep(secondsToSleep * 1000);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}

Хорошей практикой является заключение метода sleep в блок try/catch на случай, если другой поток прервет спящий поток. В этом случае мы перехватываем InterruptedException и явно прерываем текущий поток, чтобы его можно было перехватить и обработать позже. Это более важно в многопоточной программе, но все же является хорошей практикой в однопоточной программе на случай, если позже мы добавим другие потоки.

2.2. Использование TimeUnit.sleep

Для лучшей читаемости мы можем использовать TimeUnit.XXX.sleep(y) , где XXX — это единица времени, в течение которой нужно спать ( SECONDS , MINUTES и т. д .), а y — количество единиц, в течение которых нужно спать. Это использует Thread.sleep за кулисами. Вот пример синтаксиса TimeUnit :

try {
TimeUnit.SECONDS.sleep(secondsToSleep);
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
}

Однако использование этих методов на основе потоков имеет некоторые недостатки :

  • Время сна не совсем точное, особенно при использовании меньших приращений времени, таких как миллисекунды и наносекунды.
  • При использовании внутри циклов сон будет немного дрейфовать между итерациями цикла из-за выполнения другого кода, поэтому время выполнения может стать неточным после многих итераций.

3. Подход на основе ExecutorService

Java предоставляет интерфейс ScheduledExecutorService , который является более надежным и точным решением. Этот интерфейс может запланировать выполнение кода один раз после указанной задержки или через фиксированные интервалы времени.

Чтобы запустить фрагмент кода один раз после задержки, мы можем использовать метод расписания :

ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();

executorService.schedule(Classname::someTask, delayInSeconds, TimeUnit.SECONDS);

В части Classname::someTask мы указываем метод, который будет выполняться после задержки:

  • someTask — это имя метода, который мы хотим выполнить.
  • Classname — это имя класса, содержащего метод someTask.

Чтобы запускать задачу через фиксированные промежутки времени, мы можем использовать метод scheduleAtFixedRate :

ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();

executorService.scheduleAtFixedRate(Classname::someTask, 0, delayInSeconds, TimeUnit.SECONDS);

Это приведет к многократному вызову метода someTask с паузой delayInSeconds между каждым вызовом.

Помимо предоставления дополнительных параметров времени, метод ScheduledExecutorService дает более точные временные интервалы, поскольку он предотвращает проблемы с дрейфом.

4. Вывод

В этой статье мы обсудили два метода создания задержек в программах на Java.

Полный код этой статьи можно найти на Github . Это проект на основе Maven, поэтому его легко импортировать и запускать как есть.