Spring의 대표적인 비동기 작업
Spring에서는 비동기(Asynchronous) 작업을 다양한 방식으로 처리할 수 있습니다. 대표적으로 다음과 같은 Executor 구현체들이 제공됩니다.
대표적인 Executor 구현체
| SimpleAsyncTaskExecutor |
| ThreadPoolTaskExecutor |
| ThreadPoolTaskScheduler |
| 기타 ForkJoinPool 등 |
그 중 스케줄링에 특화된 ThreadPoolTaskScheduler를 살펴보겠습니다.
스케줄링 기능 활성화하기
스케줄링과 비동기 실행을 사용하려면 Spring에서 두 가지 애노테이션을 활성화해야 합니다.
@EnableAsync
@EnableScheduling
@SpringBootApplication
public class SchedulerApplication {
public static void main(String[] args) {
SpringApplication.run(SchedulerApplication.class, args);
}
}
`@EnableAsync`: 비동기 메서드 실행을 활성화
@EnableScheduling: 스케줄링 기능을 활성화
ThreadPoolTaskScheduler Bean 등록
Spring Boot는 기본적으로 taskScheduler Bean을 자동 등록해줍니다. 하지만 스레드 풀의 개수나 스레드 이름 접두사 등 커스터마이징이 필요하다면 직접 설정해주는 것이 좋습니다.
@Configuration
public class AsyncConfig {
@Bean(name = "taskScheduler")
public ThreadPoolTaskScheduler taskScheduler() {
ThreadPoolTaskScheduler scheduler = new ThreadPoolTaskScheduler();
scheduler.setPoolSize(5); // 최대 스레드 개수
scheduler.setThreadNamePrefix("Sched-"); // 스레드 이름 접두사
scheduler.initialize();
return scheduler;
}
}
-> taskScheduler라는 이름으로 Bean을 등록하면, Spring이 @Scheduled 애노테이션 기반 작업에 이 스레드 풀을 자동으로 사용합니다.
poolSize를 제한해두면 불필요하게 많은 스레드가 생성되는 것을 방지할 수 있습니다.
( 실제 운영 환경에서는 스케줄링 작업이 많은 리소스를 차지할 수 있으므로, 스레드 풀 크기를 적절히 조정하는 것이 중요 )
! 잠깐 정리 !
Spring 기본 TaskScheduler와 ThreadPoolTaskScheduler 비교
SpringBoot의 Scheduled의 기본 TaskScheduler와 커스텀한 ThreadPoolTaskScheduler는 다릅니다
Spring Boot는 특별한 설정이 없을 때 내부적으로 ConcurrentTaskScheduler를 기본 등록하며, 구현체는 사실상 단일 스레드 기반으로 동작합니다.
하나의 스케줄링 작업이 오래 걸리면, 다른 스케줄링 작업들이 밀릴 수 있습니다.
그래서 주기적인 작업이 필요한 것은 별도의 스레드로 생성하여 작업하기 위하여 ThreadPoolTaskScheduler로 따로 스레드 관리하는 형식으로 진행됩니다
ex) ThreadPoolTaskScheduler 필요 예시
- 스케줄링된 작업이 여러 개 있고 그 중 일부가 실행 시간이 길 때
- 메인이 아닌 병렬로 진행하고 싶을 때
- 스레드 이름 규칙을 정해서 로깅/모니터링을 명확히 하고 싶을 때
- 운영 환경에서 CPU나 IO 부하를 고려해 스레드 풀을 세밀하게 조정해야 할 때(-> 이 때 setPoolSize를 통해 커스텀 )
스케줄링 구체화
스케줄링할 메서드에는 @Scheduled 어노테이션을 붙입니다.
@Slf4j
@Component
public class ScheduledJobs {
/** 5초마다 실행 (이전 실행 종료와 상관없이 고정 주기) */
@Scheduled(fixedRate = 5000)
public void fixedRateJob() {
log.info("[fixedRateJob] running on thread={}", Thread.currentThread().getName());
}
/** 이전 실행이 끝난 후 10초 뒤에 재실행 */
@Scheduled(fixedDelay = 10000)
public void fixedDelayJob() {
log.info("[fixedDelayJob] running on thread={}", Thread.currentThread().getName());
}
/** 매 분 0, 20, 40초에 실행 */
@Scheduled(cron = "0,20,40 * * * * *")
public void cronJob() {
log.info("[cronJob] running on thread={}", Thread.currentThread().getName());
}
}
- @Scheduled 옵션 정리
- fixedRate: 호출 간격이 일정 (이전 실행 완료 여부와 상관없음)
- fixedDelay: 이전 실행이 끝난 후, 지정한 시간만큼 지연된 후 다시 실행
- initialDelay: 첫 실행 전에 지연 시간 설정
- cron: 크론 표현식 기반으로 실행 시점 지정
각각의 메서드들이 일정 주기를 가지고 작업을 하도록 설정하였습니다
이에 대하여 동시에 같은 스레드를 사용하지 않고 별도의 스레드들로 작업되는지를 확인해보았습니다

실행해보면 각 작업이 Sched-1, Sched-2 와 같은 이름의 별도 스레드에서 수행되는 것을 확인할 수 있습니다.
'백엔드 > SpringBoot' 카테고리의 다른 글
| [SpringBoot] SpringBoot 트랜잭션과 이벤트 발행에서의 전파 관련 트러블 슈팅 (0) | 2025.09.15 |
|---|---|
| [SpringBoot] UnitTest (1) | 2025.08.27 |
| [Spring Boot] 동시성 제어하기 (5) | 2025.08.10 |
| [Spring Boot] LazyInitializationException 을 알아보자 (5) | 2025.08.09 |
| [JPA] Page와 Slice 클래스 구분하기 (0) | 2025.08.08 |