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();
}
}
- 생성자에서 초기화를 해준다.
- 현재 시간과 실행 시간을 구한다.
- getInitialExecutionTime()을 통해서 두 시간의 차이를 구한다. => 지금부터 실행 시간까지 남은 시간
- scheduleAtFixedRate()에 위에서 얻은 결과를 토대로 호출한다.
execute(() -> System.out.println("Hello World"), 7, 0, 0);
위와 같이 호출하게 되면 7시마다 Hello World를 출력하게 된다.
참고
'Java' 카테고리의 다른 글
lombok.config 옵션 (0) | 2023.03.05 |
---|---|
BigDecimal의 toString(), toPlainString(), toEngineeringString() (0) | 2018.09.11 |
[Jackson] JsonInclude 속성에 대해 알아보자. (2) | 2018.05.23 |
Java로 날씨 알림 서비스를 만들어보자 (OOP, Clean Code) (1) | 2018.05.21 |
Java의 List를 상황에 맞게 생성해보자 ( asList(), emptyList(), singletonList() ) (2) | 2018.05.15 |