Thread.sleep: примеры (JAVA)

Приостановка выполнения потока с помощью Thread.sleep в Java
Раздел: Многопоточность, Потоки
Thread.sleep(long millis): void

Описание метода Thread.sleep

Метод Thread.sleep является статическим методом класса java.lang.Thread. Он приостанавливает выполнение текущего потока на заданное количество миллисекунд (и, опционально, наносекунд). Используется для имитации задержек, ожидания в циклах, синхронизации времени в тестах и управления частотой выполнения задач.

Аргументы:

  • long millis - количество миллисекунд сна (от 0 до 9 223 372 036 854 775 807). Если значение равно 0, поток уступает процессор другим потокам, но не останавливается гарантированно.
  • int nanos - дополнительное количество наносекунд (от 0 до 999999). Вместе с millis образует единый период ожидания. Реальная точность зависит от операционной системы и часов.

Возвращаемое значение: метод имеет тип void и не возвращает результата.

Исключение: InterruptedException - выбрасывается, если текущий поток был прерван (методом interrupt()) во время сна. Это проверяемое исключение, поэтому его необходимо обрабатывать в коде.

Метод используется для:

  • создания задержек в потоках;
  • ожидания завершения других операций (например, опроса состояния);
  • тестирования многопоточности и временных интервалов;
  • реализации таймаутов.

Примеры использования

Пример 1: базовый сон на 1 секунду

public class SleepExample {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("Начало сна");
        Thread.sleep(1000);
        System.out.println("Проснулись");
    }
}
Начало сна
(пауза 1 сек)
Проснулись

Пример 2: сон с миллисекундами и наносекундами

Thread.sleep(500, 200_000); // 500 миллисекунд + 200 000 наносекунд ≈ 500,2 мс
(пауза ~500,2 мс)

Пример 3: обработка InterruptedException

public void sleepSafe(long millis) {
    try {
        Thread.sleep(millis);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt(); // восстановить флаг прерывания
        System.out.println("Сон прерван");
    }
}
(если поток прерван во время сна - выводится "Сон прерван")

Пример 4: сон в цикле с проверкой флага

while (!stopFlag) {
    System.out.println("Работаем...");
    Thread.sleep(2000);
}
(выводится "Работаем..." каждые 2 секунды до остановки)

Альтернативы в Java

В Java существуют другие способы приостановки выполнения потока, которые могут быть более удобными в определённых ситуациях:

  • TimeUnit.sleep() - статический метод из java.util.concurrent.TimeUnit. Позволяет задавать время в различных единицах (SECONDS, MILLISECONDS, MICROSECONDS, NANOSECONDS). Он внутри вызывает Thread.sleep, но обрабатывает InterruptedException и возвращает true/false в зависимости от того, был ли прерван поток. Предпочтительнее для читаемости кода.
  • ScheduledExecutorService.schedule() - для планирования однократного или повторяющегося выполнения задачи. Не блокирует поток, а использует пул потоков. Лучше подходит для таймеров и периодических задач.
  • Object.wait(long timeout) - используется в синхронизированных блоках для ожидания уведомления (notify/notifyAll) с таймаутом. Не альтернатива простой задержке, но может служить для ожидания с освобождением монитора.
  • LockSupport.parkNanos() - низкоуровневый метод для парковки потока на заданное время. Не выбрасывает InterruptedException, но восстанавливает флаг прерывания. Используется в реализациях блокировок и синхронизаторов.

Выбор между ними зависит от задачи: для простой задержки с проверкой прерывания лучше использовать TimeUnit.sleep(), для повторяющихся задач - ScheduledExecutorService, для ожидания в синхронизации - wait() или LockSupport.

Аналоги в других языках программирования

Во многих языках есть свои функции для приостановки выполнения потока (процесса). Отличия в синтаксисе, обработке прерываний и точности.

  • PHP: функция sleep(int $seconds) - приостанавливает выполнение скрипта на целое число секунд. Не поддерживает миллисекунды (для этого есть usleep). Не выбрасывает исключения при прерывании (сигналы).
    sleep(2); // пауза 2 секунды
    (пауза 2 сек)
  • JavaScript: нет прямого блокирующего sleep. Используют асинхронные setTimeout или Promise с async/await:
    function sleep(ms) {
        return new Promise(resolve => setTimeout(resolve, ms));
    }
    await sleep(1000); // пауза 1 сек в асинхронной функции
    (не блокирует event loop)
  • Python: функция time.sleep(secs) - принимает дробное число секунд (например, 0.5). Может быть прервана сигналом (выбрасывает InterruptedError).
    import time
    time.sleep(0.5)  # пауза 500 мс
    (пауза 0.5 сек)
  • SQL (T-SQL): команда WAITFOR DELAY '00:00:01' - приостанавливает выполнение пакета на указанное время (в часах:минутах:секундах).
    WAITFOR DELAY '00:00:01'; -- пауза 1 секунда
    (пауза 1 сек)
  • C#: метод Thread.Sleep(int millisecondsTimeout) - аналогичен Java, также выбрасывает ThreadInterruptedException.
    Thread.Sleep(1000);
    (пауза 1 сек)
  • Lua: нет встроенного sleep. Используют os.execute('sleep ' .. seconds) или библиотеку socket.select (для неблокирующего).
    os.execute('sleep 1') -- пауза 1 сек
    (пауза 1 сек)
  • Go: функция time.Sleep(time.Duration) - приостанавливает текущую горутину. Duration задаётся с помощью time.Second, time.Millisecond и т.д. Не возвращает ошибок, не прерывается (прерывание горутины через каналы).
    time.Sleep(1 * time.Second)
    (пауза 1 сек)
  • Kotlin: в корутинах используется delay(millis) - неблокирующая задержка, не занимает поток. В обычном коде доступен Java Thread.sleep.
    delay(1000) // в корутине
    (пауза 1 сек без блокировки потока)

Типичные ошибки и проблемы

  • Забытая обработка InterruptedException. Если не обернуть вызов в try-catch или не объявить throws, компилятор выдаст ошибку. Кроме того, неправильное восстановление флага прерывания (замалчивание исключения) может привести к потерянным прерываниям.
    // НЕПРАВИЛЬНО: игнорируем исключение
    Thread.sleep(1000);
    // Правильно:
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        // дальнейшие действия
    }
  • Сон в UI потоке (например, Swing EDT). Блокировка главного потока приводит к зависанию интерфейса. Вместо sleep следует использовать таймеры (javax.swing.Timer) или SwingWorker.
    // НЕПРАВИЛЬНО в EDT:
    Thread.sleep(3000); // интерфейс зависнет на 3 секунды
  • Использование sleep для синхронизации. Неправильно полагаться на паузу для обеспечения порядка выполнения потоков. Нет гарантии, что другой поток завершится за указанное время. Используйте CountDownLatch, Future, join().
  • Игнорирование неточности. sleep не гарантирует точное время пробуждения из-за планировщика ОС и нагрузки. Не следует использовать его для высокоточных измерений.
  • Сон с нулевым временем. Thread.sleep(0) может быть использован для подсказки планировщику, но не гарантирует переключение контекста. Лучше использовать Thread.yield().

Изменения в последних версиях

Метод Thread.sleep существует с Java 1.0 и с тех пор не претерпел изменений в сигнатуре или поведении. В Java 5 появилась альтернатива в виде TimeUnit.sleep(), которая упрощает задание времени и корректно обрабатывает прерывания. В Java 8 и выше поведение sleep остаётся неизменным. Стоит отметить, что на разных ОС точность может незначительно отличаться, но это не связано с версиями Java.

Расширенные примеры использования

Пример 1: Поток с мягкой остановкой через флаг и прерывание

Пример java
public class StoppableTask extends Thread {
    private volatile boolean running = true;

    public void run() {
        while (running) {
            try {
                System.out.println("Выполняю работу...");
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                System.out.println("Поток прерван, завершаемся.");
                Thread.currentThread().interrupt();
                running = false;
            }
        }
    }

    public void stopTask() {
        running = false;
        this.interrupt();
    }
}
(поток выводит сообщения каждую секунду, пока не вызван stopTask() или не получено прерывание)

Пример 2: Использование sleep для имитации длительных операций в тестах

Пример java
@Test
public void testTiming() throws InterruptedException {
    long start = System.currentTimeMillis();
    Thread.sleep(1500, 500_000); // 1.5 секунды + 500 мкс
    long elapsed = System.currentTimeMillis() - start;
    // Ожидаем, что elapsed >= 1500, но может быть чуть больше
    assertTrue(elapsed >= 1500);
}
(тест проходит, если прошло не менее 1500 мс)

Пример 3: Сон с очень малыми наносекундами и его точность

Пример java
long start = System.nanoTime();
Thread.sleep(0, 100); // 100 наносекунд
long diff = System.nanoTime() - start;
System.out.println("Фактическая задержка: " + diff + " нс");
// На многих ОС минимальный квант времени > 1 мкс, поэтому diff может быть ~1 000 000 нс
Фактическая задержка: 1234567 нс (пример, зависит от системы)

Пример 4: Использование Thread.sleep в собственном пуле потоков для интервального опроса

Пример java
public void pollUntilReady(String url) throws InterruptedException {
    while (!isReady(url)) {
        System.out.println("Ожидание готовности...");
        Thread.sleep(2000);
    }
    System.out.println("Ресурс готов!");
}
(выводится "Ожидание готовности..." каждые 2 секунды, пока isReady не вернёт true)

Пример 5: Демонстрация того, что sleep не освобождает монитор

Пример java
public class SleepMonitor {
    public static void main(String[] args) {
        Object lock = new Object();
        new Thread(() -> {
            synchronized (lock) {
                System.out.println("Поток 1 захватил монитор, уснёт на 2 сек");
                try { Thread.sleep(2000); } catch (InterruptedException e) {}
                System.out.println("Поток 1 проснулся");
            }
        }).start();
        new Thread(() -> {
            // Поток 2 будет ждать освобождения монитора, а не прервёт сон первого
            synchronized (lock) {
                System.out.println("Поток 2 получил монитор");
            }
        }).start();
    }
}
Поток 1 захватил монитор, уснёт на 2 сек
(через 2 сек)
Поток 1 проснулся
Поток 2 получил монитор
(поток 2 ждал, пока sleep не закончится, потому что монитор не освобождается)

джава Thread.sleep function comments

En
Thread.sleep Приостанавливает поток на заданное время