Java

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

AlwaysPr 2018. 5. 23. 22:52

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를 출력하게 된다.

 

참고

 

How to run certain task every day at a particular time using ScheduledExecutorService?

I am trying to run a certain task everyday at 5 AM in the morning. So I decided to use ScheduledExecutorService for this but so far I have seen examples which shows how to run task every few minute...

stackoverflow.com