하나의 Spring Boot Application 인데, 이 안에 주문과 배송 등이 구현되어 있다고 가정해보자.
이 때 주문은 Virtual Thread를 사용하고, 다른 비즈니스에서는 CPU를 많이 사용하기 때문에 Platform Thread 를 사용하면서 사용할 수 있다. 만약, yml에 spring-virtual-enable-true로 설정한다면 virtual thread 로 바뀌기 때문에 Platform thread를 사용할 수 없다.
@Configuration
@Slf4j
public class SchedulerConfig {
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setThreadNamePrefix("myScheduler-");
threadPoolTaskScheduler.setPoolSize(10);
// TODO: more settings...
return threadPoolTaskScheduler;
}
@Primary
@Bean
public SimpleAsyncTaskScheduler simpleAsyncTaskScheduler(SimpleAsyncTaskSchedulerBuilder builder) {
return builder.build();
}
}
이를 위해 virtual thread용 task scheduler Bean을 만들어주고, 플랫폼 스레드를 사용하는 thread task scheduler Bean 만들어준다. 이렇게 두 개의 Bean을 만든 다음 사용하는 곳에서 골라쓰면 되는 것이다.
1) SimpleAsyncTaskSchedulerBuilder 의 경우 virtual thread가 들어가 있는 빌드를 주입받는 것이다. 그리고 builder.build 를 통해 빈으로 등록해주면 virtual thread용 스케줄러가 된다.
2) ThreadPoolTaskScheduler 의 경우 ThreadPoolTaskScheduler를 만든 다음 prefix, full-size 등을 정한 다음 빈으로 등록해주면 된다.
이 중 어느 것을 default로 동작하게 할 것인가는 @Primary를 선언함으로써 정할 수 있다.
@Service
@Slf4j
public class VirtualScheduler {
@Scheduled(fixedRate = 5000)
public void fixedRate() {
log.info("fixedRate. thread: {}", Thread.currentThread());
}
@Scheduled(fixedRate = 5000, scheduler = "threadPoolTaskScheduler")
public void fixedRate2() {
log.info("fixedRate2. thread: {}", Thread.currentThread());
}
}
그러면 스케줄러에서 아무것도 안 적으면 default Primary 스케줄러가 적용된다. 만약 scheduler 에 스케줄러 이름을 적어주면 해당되는 Bean으로 동작한다.
Task Executor 의 customized 또한 동일하다.
@Async에는 value 속성이 있다. 이는 비동기로 동작하는데, 어떤 thread pool을 사용할 것인지를 value에 적을 수 있는 것이다. 적지 않으면 default Primary로 되어 있는 thread pool을 사용하게된다. (virtual thread pool 혹은 플랫폼 thread pool)
만약 Bean 이름을 적어주면 Bean이 만든 thread pool을 사용하게 된다.
@Configuration
@Slf4j
public class ExecutorConfig {
@Bean
public SimpleAsyncTaskExecutor taskExecutor(SimpleAsyncTaskExecutorBuilder builder) {
return builder.build();
}
@Bean
public ThreadPoolTaskExecutor threadPoolTaskExecutor() {
ThreadPoolTaskExecutor threadPoolTaskExecutor = new ThreadPoolTaskExecutor();
threadPoolTaskExecutor.setCorePoolSize(10);
threadPoolTaskExecutor.setThreadNamePrefix("myThreadPool-");
// TODO: more setting...
return threadPoolTaskExecutor;
}
}
SimpleAsyncTaskExecutorBuilder 를 주입받으면 spring 은 virtual thread를 사용하는 빌더로 만들어준다. 이는 virtual thread를 사용하는 taskExecutor가 되는 것이다.
TaskExecutor 는 Primary 를 등록한다고 default Bean이 되지 않는다. spring에서는 TaskExecutor Bean이 두 개가 있으면 Bean 이름이 TaskExecutor 인 Bean이 제일 우선순위가 높다.
만약 다른 Bean을 사용하고 싶다면 @Async 에 value 값으로 Bean 이름을 등록하자.
...
궁금
executor, scheduler 뭐가 다른가
정리
1) Executor, Scheduler 모두 custom Bean을 만들어 원하는 스레드를 만들 수 있다.
2) Scheduler 는 Scheduler 어노테이션 안에, Executor 는 Executor 어노테이션 안에 원하는 Bean 이름을 등록해주면 된다.
3) Scheduler 에 default 는 Primary 로 선언한 bean 을 사용하며, Executor 는 Bean 이름이 taskExecutor 인 Bean을 default 로 사용한다.
'프로그래밍 > Java' 카테고리의 다른 글
Java21 Virtual Thread (0) | 2024.07.06 |
---|---|
Java Virtual Thread (13), 병목 현상(bottleneck) (0) | 2024.06.29 |
Java Virtual Thread (11), @scheduled 어노테이션 (0) | 2024.06.29 |
Java Virtual Thread (10), @async 어노테이션 (0) | 2024.06.29 |
Java Virtual Thread (8), Virtual Thread와 Platform Thread 성능비교 (0) | 2024.06.23 |