Taskscheduler의 동작 원리
- TaskScheduler는 PriorityQueue 기반 DelayedWorkQueue에 예약 작업을 쌓는다.
- 시간순으로 꺼내서 스레드 풀로 병렬 실행한다.
내부 클래스 동작 설명
ThreadPoolTaskScheduler
- ScheduledExecutorService 타입 필드를 가짐.
- 기본적으로 ScheduledThreadPoolExecutor를 인스턴스화해서 내부적으로 사용.
ScheduledThreadPoolExecutor
- 실제로 Runnable Task를 관리하고 실행.
- 내부적으로 DelayedWorkQueue를 사용
DelayedWorkQueue
- ScheduledFutureTask들을 PriorityQueue에 담아서 실행 예약.
ScheduledFutureTask
- 각 작업이 어떤 시간에 실행될지 나타내는 Future.
- 시간 단위로 우선순위 정렬
Taskscheduler를 Spring에 적용
사용 중인 Thread 출력
현재 JVM 프로세스에서 생성되어 살아있는 모든 스레드의 개수를 출력해준다.
log.info("[Thread Size] {}", Thread.getAllStackTraces().size());Taskscheduler의 스레드 크기
Config 설정
- 사용할 쓰레드의 크기를 정할 수 있다.(default: 1)
- 쓰레드 이름을 prefix로 설정해줄 수 있다.
@Bean
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(2);
scheduler.setThreadNamePrefix("TASK-SCHEDULER-");
scheduler.initialize();
return scheduler;
}시작
- 0부터 10까지 순차적으로 출력을 진행하는 함수를 넣어준다.
- 실행 순서는 10부터 실행되도록 설정한다.
- 실행 했을 때 Thread의 크기를 비교한다.
logThreadSize();
for (int i = 0; i < 10; i++) {
final int inner = i;
Runnable task = () -> log.info("안녕하세요 : {}", inner);
taskScheduler.schedule(task, Instant.now().plusSeconds(15 - i));
log.info("[태스크 삽입] {}", inner);
}
logThreadSize();출력 로그
- 입력된 순서와 상관없이 예약된 시간 순서대로 메소드가 실행되는 것을 확인할 수 있다.
- Thread의 크기는 미리 설정한 Thread의 크기만큼 할당된다.
- 실행 thread의 이름도 설정한 것으로 확인이 가능하다.
[line-demo] [ main] : [Thread Size] 25
[line-demo] [ main] : [태스크 삽입] 0
[line-demo] [ main] : [태스크 삽입] 1
...
[line-demo] [ main] : [태스크 삽입] 8
[line-demo] [ main] : [태스크 삽입] 9
[line-demo] [ main] : [Thread Size] 27
[line-demo] [ASK-SCHEDULER-2] : 안녕하세요 : 9
[line-demo] [ASK-SCHEDULER-1] : 안녕하세요 : 8
...
[line-demo] [ASK-SCHEDULER-2] : 안녕하세요 : 1
[line-demo] [ASK-SCHEDULER-1] : 안녕하세요 : 0추가로 도움되는 method
시간 계산하는 method
Duration.between 메소드를 사용해서 두 시간 사이의 초를 계산한다.
private long calculateDelaySeconds(LocalDateTime now, LocalDateTime targetDateTime) {
Duration duration = Duration.between(now, targetDateTime);
return Math.max(NO_DELAY, duration.getSeconds());
}현재 사용되는 쓰레드 개수
private void logThreadSize() {
log.info("[Thread Size] {}", Thread.getAllStackTraces().size());
}