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: Поток с мягкой остановкой через флаг и прерывание
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 для имитации длительных операций в тестах
@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: Сон с очень малыми наносекундами и его точность
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 в собственном пуле потоков для интервального опроса
public void pollUntilReady(String url) throws InterruptedException {
while (!isReady(url)) {
System.out.println("Ожидание готовности...");
Thread.sleep(2000);
}
System.out.println("Ресурс готов!");
}(выводится "Ожидание готовности..." каждые 2 секунды, пока isReady не вернёт true)
Пример 5: Демонстрация того, что sleep не освобождает монитор
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 не закончится, потому что монитор не освобождается)