본문 바로가기

Java

Java의 ScheduledExecutorService를 이용해서 스케줄러를 만들어보자

ScheduledExecutorService는 concurrent 패키지에 포함되어 있으며, '일정 시간 후' 또는 '주기적'으로 command(작업)를 실행시켜줄 수 있는 녀석이다.

스프링을 사용했다면 간편하게 @Scheduled를 사용했겠지만, 쌩 자바를 쓸 일이 있어서 ScheduledExecutorService를 사용해봤다.


코드 자체가 직관적이기 때문에 거두절미하고 코드를 보자.

import java.time.Duration;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;

import static java.time.LocalDateTime.now;
import static java.util.concurrent.TimeUnit.SECONDS;

public class Scheduler {

public static final String SEOUL_ZONE = "Asia/Seoul";
public static final int ONE_DAY = 1;
public static final int ONE_DAY_AS_SECOND = 24 * 60 * 60;
public static final int SINGLE_POOL_SIZE = 1;

private final ScheduledExecutorService scheduler;

public Scheduler() {
this.scheduler = Executors.newScheduledThreadPool(SINGLE_POOL_SIZE);
}

public void execute(Runnable command, int hour, int minute, int second) {
ZonedDateTime now = ZonedDateTime.of(now(), ZoneId.of(SEOUL_ZONE));
ZonedDateTime nextExecutionTime = this.getNextExecutionTime(hour, minute, second, now);
scheduler.scheduleAtFixedRate(command, this.getInitialExecutionTime(now, nextExecutionTime), ONE_DAY_AS_SECOND, SECONDS);
}

private ZonedDateTime getNextExecutionTime(int hour, int minute, int second, ZonedDateTime now) {
ZonedDateTime nextExecutionTime;
nextExecutionTime = now
.withHour(hour)
.withMinute(minute)
.withSecond(second);

if (this.isOverDay(now, nextExecutionTime))
nextExecutionTime = nextExecutionTime.plusDays(ONE_DAY);

return nextExecutionTime;
}

private boolean isOverDay(ZonedDateTime zonedNow, ZonedDateTime nextExecutionTime) {
return zonedNow.compareTo(nextExecutionTime) > 0;
}

private long getInitialExecutionTime(ZonedDateTime now, ZonedDateTime nextExecutionTime) {
Duration duration = Duration.between(now, nextExecutionTime);
return duration.getSeconds();
}

}
  1. 생성자에서 초기화를 해준다.
  2. 현재 시간과 실행 시간을 구한다.
  3. getInitialExecutionTime()을 통해서 두 시간의 차이를 구한다. => 지금부터 실행 시간까지 남은 시간
  4. scheduleAtFixedRate()에 위에서 얻은 결과를 토대로 호출한다.
execute(() -> System.out.println("Hello World"), 7, 0, 0);

위와 같이 호출하게되면 7시마다 Hello World를 출력하게 된다.


참고