원래 스프링 부트가 제공해주는 스케줄러를 쓰고 있었는데, 다른 task를 추가해야 할 일이 생겼다.

그런데 이 스케줄링이 겹치면 어떻게 될 지 궁금해졌다.

 

Scheduler 테스트 셋팅

먼저 Configuration이 선언된 곳에서 @EnableScheduling을 추가해준다.

@SpringBootApplication
@EnableScheduling
public class PlaygroundApplication {

    public static void main(String[] args) {
        SpringApplication.run(PlaygroundApplication.class, args);
    }

}

두개의 스케줄러를 등록한다.

  • test1: 1초마다 수행, 5초의 작업 시간이 걸린다.
  • test2: 1초마다 수행
@Component
public class TestScheduler {

    @Scheduled(fixedDelay = 1000) // 1초마다 수행
    public void test1() throws InterruptedException {
        Thread.sleep(5000); // 5초 작업 시간
        System.out.println("[" + Thread.currentThread().getName() + "] Test1 : " + LocalDateTime.now());
    }

    @Scheduled(fixedDelay = 1000) // 1초마다 수행
    public void test2() {
        System.out.println("[" + Thread.currentThread().getName() + "] Test2 : " + LocalDateTime.now());
    }
}

✅ 기대되는 결과: test2는 test1의 수행과 관련 없이 1초마다 수행된다.

 

결과 >

의도와는 달리, test1이 끝난 뒤 test2가 실행되는 것을 알 수 있다.

 

원인: 스프링에서 제공하는 스케줄러는 기본적으로 싱글스레드 이다.

스프링 공식문서에서도 볼 수 있듯이, 스프링에서 제공하는 @Scheduled는 싱글 스레드로 동작한다.

위 예제에서도 스레드 하나만 할당 된 것을 볼 수 있다.

 

멀티스레드로 동작하게 하려면 thread pool size를 조절해야 한다.

@Configuration
public class SchedulerConfig implements SchedulingConfigurer {
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
        threadPoolTaskScheduler.setPoolSize(10);
        threadPoolTaskScheduler.initialize();
        taskRegistrar.setTaskScheduler(threadPoolTaskScheduler);
    }
}

 

 

설정 후엔 의도된 대로 코드가 실행 되는 것을 알 수 있다.