HOWTO · Java
Java에서 몇 초를 지연시키는 방법
블로킹 일시 중지에는 Thread.sleep()를 사용하고, Java에서 지연되거나 반복되는 작업은 예약해야 하는 경우를 알아봅니다。
이 페이지의 내용
간단히 멈추려면 Thread.sleep()을 호출하세요. 지정한 시간 동안 현재 스레드가 일시 중지됩니다. 호출 스레드가 계속 작업하는 동안 나중에 실행할 작업이나 반복 작업을 예약하려면 ScheduledExecutorService를 사용하세요. 아래 예제에서는 두 방법과 인터럽트 처리, 예약 작업 정리 방법을 모두 살펴봅니다.
실행을 일시 중지하는 것은 Java 튜토리얼의 유틸리티 그룹에 속하며, 다른 일상적인 날짜, 난수, 콘솔 레시피와 함께 있습니다.
간단히 현재 스레드를 멈추려면 Thread.sleep() 사용
Thread.sleep()은 밀리초 단위의 시간을 받아 호출한 스레드를 일시 중지합니다. 다음 독립 실행 프로그램은 메시지를 출력하기 전에 1초 동안 기다립니다. main 메서드가 InterruptedException을 선언하므로, 인터럽트가 발생하면 예외를 무시하지 않고 호출자에게 전달합니다.
public class Main {
public static void main(String[] args) throws InterruptedException {
Thread.sleep(1000);
System.out.println("One second has passed.");
}
}
호출자에게 InterruptedException을 전달할 수 없는 메서드라면 예외를 잡은 뒤 Thread.currentThread().interrupt()를 호출해 인터럽트 상태를 복원하세요. 그러면 상위 코드에서 취소 요청을 확인하고 애플리케이션 정책에 따라 대응할 수 있습니다. sleep은 현재 스레드만 멈추며 프로세스의 다른 스레드에는 영향을 주지 않습니다.
지연 단위를 명확히 표현하려면 TimeUnit.sleep() 사용
TimeUnit.SECONDS.sleep(2)는 2초 동안 멈춘다는 뜻을 직접 드러냅니다. 이 방법도 호출 스레드를 차단하며 인터럽트될 수 있으므로 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.");
}
}
}
시간 단위를 명시하면 지연 시간이 더 이해하기 쉬워지는 경우 이 형식을 선택하세요. TimeUnit.sleep()은 시간 제한 대기를 읽기 쉽게 표현하는 방법입니다. 지연이 흐르는 동안 현재 스레드를 다른 작업에 사용할 수 있게 해 주지는 않습니다.
ScheduledExecutorService로 반복 작업 예약
ScheduledExecutorService를 사용하면 호출 스레드를 계속 사용할 수 있는 상태로 두면서 지연 후 또는 일정 간격으로 Runnable을 실행할 수 있습니다. scheduleAtFixedRate()에는 작업, 초기 지연, 주기, TimeUnit을 전달합니다. 실행기는 작업의 run() 메서드를 호출합니다. 작업 내용은 run()에 작성하며, run() 자체가 작업을 예약하지는 않습니다.
이 프로그램은 1초 뒤 작업을 시작하고 이후 매초 다시 실행하도록 요청합니다. 별도로 예약된 작업이 5초 뒤 반복 작업을 취소하고 실행기를 종료합니다. 실제 실행 시점의 여건에 따라 출력되는 줄의 수와 시점은 달라질 수 있습니다.
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);
}
}
반복 작업을 취소해야 할 수 있다면 반환된 ScheduledFuture를 보관하세요. 애플리케이션에서 더 이상 실행기가 필요하지 않을 때 종료하세요. 그렇지 않으면 실행기의 작업 스레드가 프로세스를 계속 실행 상태로 둘 수 있습니다. 한 번만 지연 실행하려면 반복 예약 대신 schedule()을 사용하세요.
ScheduledExecutorService에서 메서드 참조 사용
기존의 인자 없는 메서드가 작업을 나타낸다면 메서드 참조를 Runnable로 전달할 수 있습니다. 이 프로그램은 2초 뒤 메서드를 한 번 호출하도록 예약한 다음 실행기를 종료합니다. 종료하면 새 작업 제출은 막히지만 이미 대기열에 들어간 작업은 완료할 수 있습니다.
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");
}
}
현재 스레드를 멈추는 것이 목적이라면 짧은 대기에는 sleep 메서드를 사용하세요. 다른 작업을 계속 수행해야 하거나 작업을 나중에 또는 반복해서 실행해야 한다면 예약 실행기를 선택하세요. sleep은 호출 스레드를 차단하지만 실행기 정리가 필요하지 않습니다. 예약 작업은 호출 스레드를 계속 사용할 수 있게 해 주지만, 더 이상 필요하지 않을 때 실행기를 종료하고 반복 작업을 취소해야 합니다.