@Component
public class TestScheduler {
@Scheduled(fixedDelay = 1000) //작업이 끝나는 시점으로부터 1초 후에 수행
public void test1() throws InterruptedException {
Thread.sleep(10000); // 10초 대기
System.out.println("Test1: " + LocalDateTime.now());
}
@Scheduled(fixedDelay = 1000) //작업이 끝나는 시점으로부터 1초 후에 수행
public void test2() {
System.out.println("Test2: " + LocalDateTime.now());
}
}
위 코드를 보았을 때 test1이 한 번 실행될 때 test2는 10번 실행될 것으로 보이지만 실제 결과는 그렇지 않다.
콘솔을 보면 test1의 작업이 종료되어야지만 test2의 작업이 실행될 것이다.
그래서 test2의 경우에는 작업 대기가 없지만 test1과 함께 10초에 한 번씩 작업이 실행된다.
이유는 바로 스케줄러가 1개의 쓰레드로 동작하고 있기 때문이다.
이는 쓰레드를 늘리는 것으로 해결할 수 있다.
Thread Pool
Thread Pool은 여러 개의 쓰레드를 유지하고 관리하기 위해 사용된다.
쓰레드는 한 번 생성시키고 소멸하면 굉장히 많은 리소스를 소모하게 되기 때문에 매번 쓰레드를 생성시키고 없애기 보다는 Thread Pool에서는 설정된 크기의 쓰레드를 만들어 놓고 해당 쓰레드들을 계속해서 재사용할 수 있도록 관리한다.
적정 사이즈
- 쓰레드가 너무 많을 경우 : 메모리 낭비
- 쓰레드가 너무 적을 경우 : 효율성 저하
쓰레드 개수는 코드로 고정시키기 보다는 서비스가 실행되는 CPU의 코어 개수에 따라 유동적으로 생성될 수 있도록 해주는 것이 좋다.
- CPU 처리가 많은 경우 : CPU의 코어를 N개라고 했을 때, N + 1만큼의 쓰레드를 생성해주면 최적에 가까운 성능을 낼 수 있다고 봄
- I/O 작업이 많은 경우 : N * 2만큼의 쓰레드를 생성해주기도 함
단순히 많이 생성하기보다는 어떤 작업을 처리하느냐가 기준이 된다.
@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// Thread Pool 설정
ThreadPoolTaskScheduler threadPool = new ThreadPoolTaskScheduler();
// Thread 개수 설정
int n = Runtime.getRuntime().availableProcessors();
threadPool.setPoolSize(n);
threadPool.initialize();
taskRegistrar.setTaskScheduler(threadPool);
}
}
이렇게 설정을 바꿔주면 test2는 1초에 한 번씩 실행되고 test1은 10초에 한 번씩 실행될 것이다.
[Spring] Thread Pool 사용하기(feat. Scheduler)
앞의 글에서 스프링에서 스케줄링 하는 내용을 다뤘는데, 스케줄링으로 실행되어야 할 기능이 여러개 일 경우에는 한 가지 더 고려해야하는 것이 있다.바로 Thread Pool이다.위의 코드를 봤을 땐 te
velog.io